如何在grep中使用十六进制代码指定字符?


27

我正在使用以下命令对十六进制代码0900(而不是अ)到097F(而不是व)的grep字符集范围进行grep。如何使用十六进制代码代替अ和व?

bzcat archive.bz2 | grep -v '<[अ-व]*\s' | tr '[:punct:][:blank:][:digit:]' '\n' | uniq | grep -o '^[अ-व]*$' | sort -f | uniq -c | sort -nr | head -50000 | awk '{print "<w f=\""$1"\">"$2"</w>"}' > hindi.xml

我得到以下输出:

    <w f="399651">और</w>
    <w f="264423">एक</w>
    <w f="213707">पर</w>
    <w f="74728">कर</w>
    <w f="44281">तक</w>
    <w f="35125">कई</w>
    <w f="26628">द</w>
    <w f="23981">इन</w>
    <w f="22861">जब</w> 
    ...

我只想在上面的命令中使用十六进制代码代替अ和व。

如果根本无法使用十六进制代码,是否可以使用unicode而不是十六进制代码来设置字符集('अ-व')?

我正在使用Ubuntu 10.04


1
你是什​​么意思“不工作”?还会-v颠倒匹配,从您的问题文本看来,这不是您想要的。
Christian.K

@ Christian.K对不起,延迟...我已经编辑了问题,请看一看。

我还在等待一个适当的答案。:(
Dhrubo Bhattacharjee 2011年

Answers:


21

这个问题

文本通常以UTF-8编码;因此您必须使用utf-8编码中使用的字节的十六进制值。

grep "["$'\xe0\xa4\x85'"-"$'\xe0\xa4\xb5'"]"

grep '[अ-व]'

是等效的,并且它们执行基于语言环境的匹配(也就是说,匹配取决于devanagari脚本的排序规则(即,匹配不是 “ \ u0905和\ 0935之间的任何字符”,而是“ devanagari之间的任何排序A和devanagari VA”;可能会有差异。

另一方面,您有以下内容(请注意-P):

grep -P "\xe0\xa4[\x85-\xb5]"

它将与这些字节值进行二进制匹配。


2
请解释前缀"["$'和后缀"]"
Jonathan Komar

6

如果外壳转义已足够,则可以使用如下$'\xHH'语法:

grep -v "<["$'\x09\x00'"-"$'\x09\x7F'"]*\s"

这足以满足您的用例吗?


echo 'अ-व' | hd给我e0 a4 85 - e0 a4 b5
enzotib 2011年

事实上,OP给Unicode值,不是十六进制转储UTF-8编码: - /由于grep没有与任何LIB联系,我想这是不可能有通过grep的执行范围转换: - /
斯特凡希门尼斯

1
顺便说一句,zsh能够解释"\u0900""\u097F",但是行为将取决于UTF-8编码范围是连续的(可能是连续的)。
斯蒂芬·吉梅内斯

没有grep -v“ <[” $'\ x09 \ x00'“-” $'\ x09 \ x7F'“] * \ s”给出以下输出<wf =“ 16929”> x </ w> <wf =“ 10995“> F </ w> <wf =” 2548“> FF </ w> <wf =” 762“> FFFFFF </ w> <wf =” 655“> FFFF </ w> <wf =” 266“ > xx </ w> <wf =“ 215”> FFF </ w> <wf =“ 117”> xxx </ w>...。这是不期望的。:(,我可以使用unicode代替十六进制代码或字符集('अ-व')吗?
Dhrubo Bhattacharjee

6

0x0900您编写的“十六进制”值恰好也是十六进制的UNICODE代码点的值。

十六进制代码0900(而不是अ)

我相信您要说的是十六进制的UNICODE代码点:U0905

U-0900处的字符不是您使用的字符:
该字符是U0905,它是此Unicode页的一部分,或在此页中列出。

bash(默认安装在Ubuntu中)中,或直接在以下位置使用该程序:(/usr/bin/printf但不是在shprintf中),可以使用以下命令生成Unicode字符:

$ printf '\u0905'

$ /usr/bin/printf '\u0905'

但是,取决于一个代码页,该字符可以由几个字节流表示,该字符来自一个代码点号。
显而易见,\U0905它出现0x09 0x05在UTF-16(UCS-2等)
0x00 0x00 0x09 0x05UTF-32中。
它可能并不明显,但是在utf-8中,它表示为0xe0 0xa4 0x85

$ /usr/bin/printf '\u0905' | od -vAn -tx1
e0 a4 85

如果控制台的语言环境类似于en_US.UTF-8

我说的是外壳程序,因为它是将字符串转换为应用程序接收到的内容的外壳程序。这个:

grep "$(printf '\u0905')" file

使grep“看到”您需要的字符。
要了解上面的行,您可以使用echo:

$ echo grep "$(printf '\u0905')" file
grep  file

然后,我们可以根据您的要求构建字符范围:

$ echo grep "$(printf '[\u0905-\u097f]')" file
grep [अ-ॿ] file

那回答了你的问题:

如何使用十六进制代码代替अ和व?


到目前为止,这是最好的答案-它明确解决了外壳中Unicode点表示的问题,并说明了如何在它们之间以十六进制代码来回切换。
stefano

2

我们希望将非ascii开双引号和闭合双引号转换为常规双引号(“)。还将非ascii单引号转换为常规单引号(')。

在文件中查看它们(ubuntu bash shell):

$ grep -P "\x92" infile.txt  (single)
$ grep -P "\x93" infile.txt  (open double)
$ grep -P "\x94" infile.txt  (close double)

翻译他们:

$ /bin/sed "s/\x92/'/g" a.txt > b.txt
$ /bin/sed 's/\x93/"/g' b.txt > c.txt
$ /bin/sed 's/\x94/"/g' c.txt > d.txt
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.