grep regex .* 不匹配所有内容

grep regex .* 不匹配所有内容

我最近开始使用诸如grep、、等工具wccat因为我必须处理一些非常大的 CSV 文件(>10GB),这些文件没有完全正确地分隔(例如,出现分隔符里面一些领域。

在处理其中一个文件时,我运行了以下命令,试图找出一种方法来正确识别哪些实例是;分隔符并将其替换为其他字符:

grep -v -n --text "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9].*[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" < Transactions.csv

正则表达式可能可以做得更好,但无论如何;令人惊讶的是,除其他外,上面的代码输出以下行:

12345678:2016-10-25;12345678912345;2016-10-25;gobbledegook �IDNR: 69 ;12345.67;.00;2003-09-05;12345678;2003-09-03;stuff stuff         ;12345 fgadfkjgbsdkb;12/3/45678/9

(因为这实际上是交易数据,我更改了大多数字段的值,除了有问题的)也许我有点傻,但为什么上面的正则表达式不匹配该行?似乎正则表达式.*由于某种原因不匹配该字符。

我怀疑该文件是使用 UTF-16 编码保存的,如果有任何区别的话。

编辑:感谢 @exore 的回答。事实证明,我的文件是用 ISO-8859-15 编码的,我能够通过将grep包含特殊字符的行(相对较少)ping 到文件中并在 gedit 中打开来解决这个问题。然后我将iconv其转换为 utf8,之后它工作正常!

答案1

这是一个典型的字符编码问题。.表示任何字符。但哪个字节序列是合法字符则取决于编码。在不了解编码的情况下处理文本肯定会失败。您的 grep 命令可能期望 UTF-8 编码的字符串。UTF-8 是一种多字节编码,这意味着某些字符由多个字节表示。但是,并非所有字节序列都是有效的。例如,请参阅维基百科有关 UTF-8 的文章

当 grep 遇到不是预期编码中的有效字符的字节序列时,它无法将其识别为字符,该行不匹配,而是输出。由于您的终端也无法识别该字符,因此您会得到一个

您的情况有一个解决方法。告诉 grep 不要担心编码,并将一个字节视为一个字符。

env LANG=C grep ....

或者可能

env LANG=C LC_ALL=C grep ....

您可以轻松测试:

创建2个文件,一个为utf-8编码,一个为utf-16-be:

$ echo éléphant | tee file.std | iconv -f utf8 -t utf16be >file.utf16be

检查文件内容:

$ cat file*
éléphant
�l�phant

尝试 grep。utf16be 字符串无法识别,没有输出:

$ grep '^.*$' file*
file.std:éléphant

根本不要使用编码。一个字节是一个字符。所有字符串都匹配� 只是意味着终端无法将 utf16be 序列识别为有效的 utf-8 字符。请注意使用 来-a告诉 grep 将二进制视为一些文本。

$ env LANG=C grep -a '^.*$' file*
file.std:éléphant
file.utf16be:�l�phant

或者,如果您知道编码,则可以iconv先转换文件,然后使用 grep。以下方法之一应该有效。

iconv -f utf16   -t utf8 < file | grep ...
iconv -f utf16le -t utf8 < file | grep ...
iconv -f utf16be -t utf8 < file | grep ...

相关内容