在bash中,如何将Unicode代码点[0-9A-F]转换为可打印字符?


Answers:


16

您可以将Gash coreutils中的bash的echo或/ bin / echo与iconv结合使用:

echo -ne '\x09\x65' | iconv -f utf-16be

默认情况下,iconv转换为您的语言环境编码。Perl可能比依赖特定的shell或echo命令更可移植。我所知道的大多数UNIX系统都有Perl可用,甚至还有几个Windows端口。

perl -C -e 'print chr 0x0965'

在大多数情况下,我需要使用内置支持的Vim / GVim这样的编辑器。在插入模式下,按Ctrl-V,再按u,然后键入四个十六进制字符。如果要使用U + FFFF以外的字符,请使用大写U并键入8个十六进制字符。Vim还支持自定义易于制作的键盘映射。它将一系列字符转换为另一个符号。例如,我开发了一个名为www的键盘映射,它将TM转换为™,(C)转换为©,(R)转换为®,依此类推。我也有必要时使用Klingon的键盘映射。我确信Emacs也有类似的东西。如果您使用的是包含GVim和GNOME Terminal的GTK +应用程序,则可以尝试使用Control-Shift-u和4个十六进制字符来创建Unicode字符。我确信KDE / Qt有类似的东西。

更新:从Bash 4.2开始,它现在似乎是内置功能:

echo $'\u0965'

更新:而且,如今,Python示例可能比Perl更可取。这适用于Python 2和3:

python -c 'print(u"\u0965")'

谢谢... perl的一个尼斯和简洁,但它有我有点困惑的是,它知道如何对待价值为UTF-16BE。我想这就是在“CHR”的意思...
Peter.O

@fred很好。Perl示例对语言环境敏感。-C启用完整的Unicode处理,但是该示例有效,因为我的语言环境使用了Unicode示例。如果将LANG设置为C,则会收到有关打印中的宽字符的警告,但仍会打印。如果我chr 0xa2在UTF-8语言环境中打印,我会得到一个美分符号¢,但是如果我使用LANG = C,我会得到-因为它打印出在UTF-8中无效的字节0xa2。Vim / GVim示例对语言环境是半敏感的。更正确的是,对文件进行编码。如果您在非UTF-8语言环境中启动Vim,则需要:set encoding=utf-8
penguin359

@fred我应该指出,如果Perl是在UTF-8之类的Unicode语言环境中启动的,Perl会将chr的值视为Unicode代码点。代码点是表示字符的唯一数字,不与任何一种编码(例如UTF-16BE或UTF-8)绑定。打印出来时,它将转换为正确的编码。例如,楔形文字符号A是代码点U + 012000。我可以chr 0x12000在Perl 中使用(假设Unicode是活动的)来表示它。在UTF-16BE中,这是0xd8、0x08、0xdc和0x00。您的字符是U + 0965,在UTF-16BE中恰好是字节0x09,后跟0x65。
penguin359

@ penguin359 ..谢谢,有一天(希望)我会好好看看perl。.似乎难以理解,但最初的sed和regex也是如此,现在很容易...也许有点像vim; 陡峭的学习曲线,那么一帆风顺....这是很好的阅读你的解释...它铺平了道路..
Peter.O

我只是(重新)发现,Steven D的 printf灵魂无法处理unicode范围的ASCII块,因此您的perl答案现在是最好的(根据我的特殊要求)。 ,但我已经忘记了。这是有关其限制的问题/答案... 为什么printf报告除三个(ASCII范围)Unicode代码点
以外的

13

巴什4.2(2011年发布)补充支持echo -e '\u0965'printf '\u0965'printf %b '\u0965'echo $'\u0965'同样的工作。

http://tiswww.case.edu/php/chet/bash/FAQ

o   $'...', echo, and printf understand \uXXXX and \UXXXXXXXX escape sequences.

谢谢...我仍然主要在Ubuntu 10.04中使用bash 4.1.5,但是很高兴知道它现在在4.2中可用。(+1)
Peter.O

1
+1; 请注意,bash 4.2.x版本存在一个错误,其中0x80and 之间的值0xff128 - 255即在扩展的ASCII范围内)的值未正确进行UTF8编码,而是仅通过传递,从而导致无效的UTF8字符,某些终端将其呈现为?。截至(至少)4.3.11此问题已解决;如果echo $'\ued'renders í,则错误存在。
mklement0 2014年

5

如果您有GNU coreutils,请尝试printf

$ printf '\u0965\n'

echo 如果您的控制台使用的是UTF-8,并且您使用的是UTF-8编码,则可以完成此工作:

$ echo -e '\xE0\xA5\xA5'

您可以在此处找到Unicode到UTF-8十六进制编码的表:http : //www.utf8-chartable.de/。您可以使用多种脚本语言将Unicode代码点转换为十六进制。这是使用python的示例:

python -c "print(unichr(int('0965', 16)).encode('utf-8').encode('hex'))"

以下是一个Perl脚本,它将参数转换为正确的十六进制值(此处有许多不必要的括号):

#!/usr/bin/perl
use strict;
use warnings;
use 5.010;
use Encode;

foreach (@ARGV) {
    say unpack('H*', encode('utf8', chr(hex($_))))
}

例如,

./uni2utf 0965
e0a5a5

当然,如果您具有Perl或Python,也可以使用这些字符来打印字符。


谢谢.. echo我不会做我想要的,因为代码点是2字节UTF-16 Big-Endian ..但是您提醒我,这里有2个 printf函数!(我认为printf可以做到,而且似乎我调用了错误的代码)... $(which printf)有效...感谢python的示例..但是对于这个(我的学习曲线),我试图坚持下去尽可能将“ bash”作为涉及的唯一编写语言。.(当我对bash足够适应时,我会陷入Python的困境……顺便说一句,.encode('hex')这超出了我所需要的一步。.(我认为它看上去那里有点忙:)
Peter.O 2011年

是的,.encode('hex')只是为了获得对我来说似乎可以与echo一起工作的十六进制代码。很高兴至少其中一部分是有帮助的。
Steven D

我刚刚看过您的perl片段..谢谢...列出这些各种解决方案是一件好事... printf正是我想要的(按照zsh示例,一个命令)... ..我可以很好地发布我的不使用另一种脚本语言方法,该方法适用于十六进制数据流(无\ u等)
。–

我特别喜欢上述内容的简洁性printf,但是它不能处理低于``\ u00A0 ... I've just re-discovered something I already knew (but dropped off the radar)... Here is a Question I asked about 4 months ago; [Why does printf report an error on all but three (ASCII-range) Unicode Codepoints](http://askubuntu.com/questions/20806/why-does-printf-report-an-error-on-all-but-three-ascii-range-unicode-codepoints)... So *penguin359's* perl`的值。现在,解决方案看起来还不错:) ..这是一次简单的练习,我在“易于键入”之后,所以我给出他是perl
Peter.O

2

更新:这是一种执行单个Unicode值的bash方法...(通过“ bash”表示,我的意思是:不使用任何其他脚本语言)..感谢Gilles在此Askubuntu Q / A中的建议。
根据此链接:重新编码(过时的iconv,dos2unix,unix2dos)。编辑:但是根据下面的评论,“过时”可能仅表示“替代”

      echo -n 0x0965 |recode UTF-16BE/x4..UTF-8

这是一种处理原始十六进制转储作为输入的方法(即,没有转义前缀,如\ u0965,也没有\ x09 \ x65)..
xxd是一种十六进制转储实用程序(打包为vim-common),可以还原原始十六进制转储转储代表的字符... Unicode代码点是UTF-16BigEndian,这正是十六进制转储的含义。.
xxd在还原模式下,将接受带有换行符的十六进制值流。

该脚本创建一个UTF-16BE流,然后将其还原为原始字符。
最后一行包含两个所需的命令;xxdiconv

for line in \
  "Matsuo Basho (1644-1694)" \
  "  pond" \
  "  frog jumps in" \
  "  plop!"
do 
  echo "$line" |iconv -f "$(locale charmap)" -t "UTF-16BE" |xxd -ps -u 
done |
#    (---this is the **revert** code---) 
tee >(xxd -p -u -r |iconv -f "UTF-16BE") ;echo

这是输出(首先显示UTF-16BE十六进制转储输入)。
注意; xxd用60进制数字的换行符分割其自身的输出...还原选项将忽略这些换行符。它将忽略任何/所有换行符(因为不是十六进制数字)。

004D0061007400730075006F00200042006100730068006F002000280031
003600340034002D00310036003900340029000A
002000200070006F006E0064000A
0020002000660072006F00670020006A0075006D0070007300200069006E
000A
002000200070006C006F00700021000A

Matsuo Basho (1644-1694)
  pond
  frog jumps in
  plop!

由于似乎您在答案中使用了penguin359的信息,因此您可以考虑将其答案标记为正确,而不是我的答案。
史蒂文D

@Steven D:一个值得注意的评论,但“似乎”是有效的词。我已经使用了几天这样的iconv,这让我想知道是否只有一个命令。我已经在Windows(C ++)中完成了类似的全文件处理,因此我对Unicode有一个理性的理解。我真的是在追求一种快速简单的bash方法。“ bash”是指:使用bash脚本语言;不是来自bash的python / perl)。我将其添加为答案,因为它对于阅读此页面的人可能具有一定的价值。对于整个文件来说这是一个很好的选择。您printf是我的最佳答案。
Peter.O 2011年

2
我不会说recode已过时,iconv实际上是recode比iconv早,并且如今,默认情况下iconv比recode更为常见(例如,在Linux上,因为libc附带了iconv,所以几乎总是安装了iconv)。
吉尔(Gilles)'所以

谢谢..我想知道有关..该网页不完全明确的参考...所以它更多的是一种另类的...
Peter.O

1

假设操作系统的默认编码为UTF-8(对于大多数当前发行版为true),则可以直接使用bash转换任何UNICODE代码点:

echo -e "Unicode Character 'DEVANAGARI DOUBLE DANDA' (U+0965) \U0965"

当然,仅当您具有正确的字体时,该字形才会正确显示。从bash 4.3开始,所有代码点将正常工作。这两个内置选项也将起作用:

printf "%b" "Unicode Character (U+0965) \U0965 \n"
echo $'Unicode Character (U+0965) \U0965'

请注意,对于bash 4.2,从0x80到的Unicode代码点0xFF编码不正确(bash错误)。要变通解决此问题,您必须查看此站点上的程序(也有助于深入了解将数字转换为char的问题。


在bash 4.3和zsh中对我有效。您可以链接到bash 4.2的错误报告吗?
Mikel

在我看来,这就像是正确的错误:https://lists.gnu.org/archive/html/bug-bash/2012-02/msg00035.html说明:\ u和\ U错误地将\ u80和\ uff之间的值编码

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.