【问题标题】:How to convert between the unicode forms: string, name, number如何在 unicode 形式之间进行转换:字符串、名称、数字
【发布时间】:2022-01-14 12:03:39
【问题描述】:

我最近使用 unicode 比较频繁,想知道是否有命令行工具可以在其形式之间转换 unicode。

很高兴能够说:

uni_convert "☃" --string

并且知道字符串在 unicode 中定义为“SNOWMAN”。

【问题讨论】:

    标签: bash perl one-liner


    【解决方案1】:

    Perl 的Unicode-Tussle 分发版附带有用的uniprops

    $ uniprops '☃'
    U+2603 ‹☃› \N{SNOWMAN}
    ...
    
    $ uniprops 'U+2603'
    U+2603 ‹☃› \N{SNOWMAN}
    ...
    
    $ uniprops 'SNOWMAN'
    U+2603 ‹☃› \N{SNOWMAN}
    ...
    

    如果您正在编写代码,则需要charnames

    Input  To get $code
    =====  ==============================
    $char  ord($char)
    $name  charnames::vianame($name)
    
    Input  To get $char                    
    =====  ==============================
    $code  chr($code)
    $name  chr(charnames::vianame($name))
    
    Input  To get $name
    =====  ==============================
    $code  charnames::viacode($code)
    $char  charnames::viacode(ord($char))
    

    vianame 接受官方别名(例如,LF 代表 LINEFEED)。如果希望接受它,您需要自己解析 U+ 符号。 ($code = hex(s/^U\+//r);)

    例子:

    use strict;
    use warnings;
    use feature      qw( say );
    use experimental qw( regex_sets );
    
    use utf8;                              # Source encoded using UTF-8.
    use open ":std", ":encoding(UTF-8)";   # Terminal provides/expects UTF-8.
    
    use charnames qw( :full );
    use Encode    qw( decode_utf8 );
    
    @ARGV == 1
       or die("usage\n");
    
    my $s = decode_utf8($ARGV[0]);
    
    for my $cp ( unpack "W*", $s ) {
       my $ch = chr($cp);
       if ( $ch =~ /(?[ \p{Print} - \p{Mark} ])/ ) {   # Not sure if good enough.
          printf "‹%s› ", $ch;
       } else {
          print "--- ";
       }
    
       printf "U+%X ", $cp;
    
       say charnames::viacode($cp);
    }
    
    $ uni_id ☃
    ‹☃› U+2603 SNOWMAN
    
    $ uni_id çà
    ‹ç› U+E7 LATIN SMALL LETTER C WITH CEDILLA
    ‹à› U+E0 LATIN SMALL LETTER A WITH GRAVE
    

    其他资源:

    【讨论】:

    【解决方案2】:

    这里有一个 awk 可以做到这一点。

    从提供最新名称的 unicode.org 下载 this file

    然后:

    q=$(printf '%x\n' \'☃)
    awk '/^[[:xdigit:]]+/{
        str=$0
        sub(/^[[:xdigit:]]+[[:blank:]]+/,"",str)
        names[$1]=str
    }
    END{ print names[q] }
    ' q="$q" names.txt
    

    打印:

    SNOWMAN
    

    如果你想走另一条路:

    cp=$(awk '/^[[:xdigit:]]+/{
        str=$0
        sub(/^[[:xdigit:]]+[[:blank:]]+/,"",str)
        other_names[str]=$1
    }
    END{ print other_names[q] }
    ' q="SNOWMAN" names.txt)
    
    echo -e "\u${cp}"
    

    打印:

    如果您有 GNU awk,您可以轻松地将十六进制索引转换为十进制并可以从内部打印。这允许通过定义 qr 来使用单个源文件并以一种或另一种方式使用:

    gawk '/^[[:xdigit:]]+/{
        str=$0
        sub(/^[[:xdigit:]]+[[:blank:]]+/,"",str)
        names[$1]=str
        other_names[str]=$1
    }
    END{ print q ? names[q] : sprintf("%c", strtonum("0x" other_names[r])) }
    ' r='SNOWMAN' names.txt
    ☃
    
    gawk '/^[[:xdigit:]]+/{
        str=$0
        sub(/^[[:xdigit:]]+[[:blank:]]+/,"",str)
        names[$1]=str
        other_names[str]=$1
    }
    END{ print q ? names[q] : sprintf("%c", strtonum("0x" other_names[r])) }
    ' q=$(printf '%x\n' \'☃) names.txt
    SNOWMAN
    

    【讨论】:

    • 换个方式怎么样?
    • 我不知道有这样的文件。很高兴知道?
    • Re "从提供最新名称的 unicode.org 下载此文件。",别忘了aliases
    【解决方案3】:

    我将代码分成一个文件并创建了一个 repo: https://github.com/poti1/uni_convert

    【讨论】:

    • 为什么不直接使用一个实际的 perl 脚本文件,而不是一个用 shell 函数包裹的巨大的单行代码?
    • 哦,Term::ANSIColor 代替硬编码的转义序列很有用。
    • 我倾向于将这些添加到我的 bashrc 中,而不是每个脚本或函数都有一个文件。当脚本足够大时(就像现在?),我会把它移到一个单独的文件中。
    • 我见过 Term::ANSIColor 被其他人使用。我猜它比使用转义字符更好?
    猜你喜欢
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-13
    • 2019-08-23
    • 2011-08-25
    相关资源
    最近更新 更多