将ASCII字符转换为“<uxxx>”unicode表示法</uxxx>的脚本

时间:2011-04-03 06:28:20

标签: python string bash ascii

我正在对Linux语言环境文件/usr/share/i18n/locales进行一些更改(如pt_BR),并且必须在Unicode中指定格式字符串(如%d-%m-%Y %H:%M),其中每个(在这种情况下,ASCII)字符表示为<U00xx>

所以这样的文字:

LC_TIME
d_t_fmt "%a %d %b %Y %T %Z"
d_fmt   "%d-%m-%Y"
t_fmt   "%T"

必须:

LC_TIME
d_t_fmt "<U0025><U0061><U0020><U0025><U0064><U0020><U0025><U0062><U0020><U0025><U0059><U0020><U0025><U0054><U0020><U0025><U005A>"
d_fmt   "<U0025><U0064><U002D><U0025><U006D><U002D><U0025><U0059>"
t_fmt   "<U0025><U0054>"

因此,我需要一个命令行脚本(无论是bash,Python,Perl还是其他),它会接受%d-%m-%Y之类的输入并将其转换为<U0025><U0064><U002D><U0025><U006D><U002D><U0025><U0059>

输入字符串中的所有字符都是ASCII字符(从0x200x7F),所以这实际上是一个更加绚丽的“char-to-hex-string”转换。

有人可以帮帮我吗?我在bash脚本编写方面的技能非常有限,在Python中甚至更糟。

优雅,解释的解决方案的奖金。

谢谢!

(顺便说一下,这将是我previous question

的“反向”脚本

4 个答案:

答案 0 :(得分:7)

每个带文件输入的字符

如果你想将文件的每个字符转换为unicode表示,那么这就是这个简单的单行

while IFS= read -r -n1 c;do printf "<U%04X>" "'$c"; done < ./infile

STDIN上的每个字符

如果你想制作一个类似于unix的工具,将STDIN上的输入转换为类似unicode的输出,那么使用它:

uni(){ c=$(cat); for((i=0;i<${#c};i++)); do printf "<U%04X>" "'${c:i:1}"; done; }

概念证明

$ echo "abc" | uni
<U0061><U0062><U0063>

仅双引号之间的字符

#!/bin/bash

flag=0
while IFS= read -r -n1 c; do
    if [[ "$c" == '"' ]]; then
        ((flag^=1))
        printf "%c" "$c"
    elif [[ "$c" == $'\0' ]]; then
        echo
    elif ((flag)); then
        printf "<U%04X>" "'$c"
    else
        printf "%c" "$c"
    fi
done < /path/to/infile

概念证明

$ cat ./unime
LC_TIME
d_t_fmt "%a %d %b %Y %T %Z"
d_fmt   "%d-%m-%Y"
t_fmt   "%T"
abday "Dom";"Seg";/
here is a string with "multiline
quotes";/

$ ./uni.sh
LC_TIME
d_t_fmt "<U0025><U0061><U0020><U0025><U0064><U0020><U0025><U0062><U0020><U0025><U0059><U0020><U0025><U0054><U0020><U0025><U005A>"
d_fmt   "<U0025><U0064><U002D><U0025><U006D><U002D><U0025><U0059>"
t_fmt   "<U0025><U0054>"
abday "<U0044><U006F><U006D>";"<U0053><U0065><U0067>";/
here is a string with "<U006D><U0075><U006C><U0074><U0069><U006C><U0069><U006E><U0065>
<U0071><U0075><U006F><U0074><U0065><U0073>";/

解释

非常简单

  1. while IFS= read -r -n1 c;:一次迭代输入的一个字符(通过-n1)并将char存储在变量c中。 IFS=-r标志位于此处,因此read内置函数不会分别尝试进行单词拆分或解释转义序列。
  2. if [[ "$c" == '"' ]];:如果当前字符是双引号
  3. ((flag^=1)):从0-> 1或1-> 0
  4. 反转标志的值
  5. elif [[ "$c" == $'\0' ]];:如果当前的字符是NUL,那么echo换行符
  6. elif ((flag)):如果flag为1,则执行unicode transliteration
  7. printf "<U%04X>" "'$c":执行unicode音译的魔力。请注意,$c之前的单引号是必需的,因为它告诉printf我们正在为它提供数字的ASCII表示。
  8. else printf "%c" "$c":打印出没有执行unicode音译的角色

答案 1 :(得分:5)

使用Python

#!/usr/bin/env python3.2
import sys
text = sys.argv[1]
encoded = "".join("<U{0:04X}>".format(ord(char)) for char in text)
print(encoded)

用法:

$ python3 file.py "enter_input"
<U0065><U006E><U0074><U0065><U0072><U005F><U0069><U006E><U0070><U0075><U0074>

(同样的脚本应该适用于python 3.x和2.x.只需更改shebang中的版本即可 你拥有的那个。)

说明:

  1. 我们需要导入the sys module来读取命令行参数。

  2. sys.argv list是所有命令行参数的列表。条目[0]是程序名称,条目[1]是第一个参数,等等。

  3. f(char) for char in textgenerator expression。它将为text变量中的每个字符循环,然后在其上应用函数f,最后将结果作为惰性列表(iterable)收集。

  4. ord(char)找到角色的Unicode代码点。

  5. "<U{0:04X}>".format(x)是一个字符串格式化方法,如名称所述。格式字符串采用1个输入x,并格式化为04X format,表示前导零,宽度为4,大写十六进制。

  6. "".join(it)连接延迟列表中的所有元素(可迭代)it""表示分隔符是空字符串。

  7. print(encoded)将字符串encoded写入stdout。

答案 2 :(得分:0)

echo -n "aä" | ruby -KU -e '$<.chars{|c| print "<U"+"%04X"%c.unpack("U*")[0]+">"}; puts'

输出<U0061><U00E4>

-KU = $KCODE = "U"

答案 3 :(得分:0)

Shell脚本解决方案:

#!/bin/sh

while IFS= read -r -n1 c;
    do printf "<U%04X>" "'$c";
done

这会读取标准输入并打印到标准输出(假设您已将脚本放入可执行文件 toUnicode.sh ):

> echo "hello" | toUnicode.sh
<U0068><U0065><U006C><U006C><U006F><U0000>

这会打印EOF字符(<U0000>),但您可以更改此脚本以满足您的需要,无论您是想一次读取一行还是修改它或以其他方式改变它。