Phi*_*pos 4 character-encoding shell-script text-processing sort unicode
上下文(如果你不在乎,请跳过;如果你怀疑我完全走错了路,请阅读)
\n对于内存较小的嵌入式系统,我想生成仅包含实际需要的字形的字体。因此,在构建时,我需要扫描语言文件,从字符串中提取字符并使用它们的代码作为字体生成工具的参数。
\n包含相关字符串的翻译文件(当然,这只是一个例子,但至少它涵盖了一些 unicode 内容)
\nTEXT_1=Foo\nTEXT_2=Bar\nTEXT_3=Baz\nTEXT_4=\xc3\x9cnic\xc3\xb8d\xc3\xa9\nTEXT_5=\xce\xb5\xce\xbb\xce\xbb\xce\xb7\xce\xbd\xce\xb9\xce\xba\xce\xac\nRun Code Online (Sandbox Code Playgroud)\n预期产出
\n0x42,0x61,0x72,0x42,0x61,0x7A,0x46,0x6F,0x6F,0xDC,0x6E,0x69,0x63,0xF8,0x64,0xE9,0x3B5,0x3BB,0x3BB,0x3B7,0x3BD,0x3B9,0x3BA,0x3AC\nRun Code Online (Sandbox Code Playgroud)\n到目前为止我的方法
\n该脚本只是执行我所描述的操作:sed读取文件,提取字符串,并准备将其格式化printf,sort -u删除重复项:
for char in $(sed "s/[^=]*=//;s/./'& /g" myLang.translation|sort -u); do\n printf "0x%02X\\n" $char\ndone\nRun Code Online (Sandbox Code Playgroud)\n这适用于这个例子,但感觉丑陋、不可靠、错误,对于真实文件来说可能很慢,所以你能说出一个更好的工具、更好的方法、更好的东西吗?
\n和perl:
perl -C -lne '
if (/=(.*)/) {$c{$_}++ for split //, $1}
END{print join ",", map {sprintf "0x%X", ord$_} sort keys %c}
' your-file
Run Code Online (Sandbox Code Playgroud)
给出:
0x42,0x46,0x61,0x63,0x64,0x69,0x6E,0x6F,0x72,0x7A,0xDC,0xE9,0xF8,0x3AC,0x3B5,0x3B7,0x3B9,0x3BA,0x3BB,0x3BD
Run Code Online (Sandbox Code Playgroud)
-C如果语言环境使用 UTF-8 作为其字符映射,则执行 UTF-8 I/O-ln sed -n模式,其中代码在输入的每一行上运行。-l从输入中删除行分隔符,并将其添加回输出中(执行 a $\ = $/)-e 'code'指定要在命令行而不是从脚本运行的代码。/=(.*)/要匹配的行至少包含一个=捕获$1 (第一个捕获组)中第一次出现之后的内容。split //, $1用空分隔符将其拆分为单个字符$c{$_}++ for that-above循环该字符列表并递增相应的关联数组元素。%c将字符映射到其出现次数。我们在这里不使用该计数。END{code},code只有跑到最后。sort keys %c按词法对该关联数组的键进行排序map { code } @list通过在每个元素上应用代码来转换列表。ord$_获取字符的数值。sprintf "0x%X"将其格式化为十六进制(大写ABCDEF,但小写0x)。join ",", @list加入列表,print打印它,后跟$\(换行符)。在 zsh 中(可能效率低很多):
$ set -o cbases -o extendedglob
$ LC_COLLATE=C
$ echo ${(j[,])${(ous[])"$(<your-file cut -sd= -f2- | tr -d '\n')"}/(#m)?/$(([#16]#MATCH))}
0x42,0x46,0x61,0x63,0x64,0x69,0x6E,0x6F,0x72,0x7A,0xDC,0xE9,0xF8,0x3AC,0x3B5,0x3B7,0x3B9,0x3BA,0x3BB,0x3BD
Run Code Online (Sandbox Code Playgroud)
或者不使用外部实用程序:
$ set -o cbases -o extendedglob
$ LC_COLLATE=C
$ echo ${(j[,])${(@ous[])${(f)"$(<your-file)"}#*=}/(#m)?/$(([#16]#MATCH))}
0x42,0x46,0x61,0x63,0x64,0x69,0x6E,0x6F,0x72,0x7A,0xDC,0xE9,0xF8,0x3AC,0x3B5,0x3B7,0x3B9,0x3BA,0x3BB,0x3BD
Run Code Online (Sandbox Code Playgroud)
"$(<you-file)"文件的内容,删除了尾随换行符,并用引号引起来,因此它不是 IFS 分割的${(f)param}按行分割f以将行作为列表获取${array#*=}从数组元素中删除最短的前导部分匹配*=。@确保 列表处理的标志o按词法顺序(基于 C 语言环境中的代码点)unique 删除重复项s[]分裂成单独的字符。${array/(#m)?/$(([#16]#MATCH))}将感谢中捕获的字符 ( ?)替换为以 16 为基数格式化的值(在算术表达式中) 。有了这个选项,就可以代替$MATCH(#m)#MATCH[#16]cbases0xBEEF16#BEEFj[,]加入,.将其分解为单独的步骤将使其更清晰:
set -o cbases -o extendedglob
LC_COLLATE=C
contents=$(<your-file)
lines=( ${(f)contents} )
values=( ${lines#*=} )
chars=( ${(@ous[])values} )
codepoints=( ${chars/(#m)?/$(( [#16] #MATCH ))} )
echo ${(j[,])codepoints}
Run Code Online (Sandbox Code Playgroud)