从文本文件中删除未知的Unicode字符-sed,其他bash / shell方法


9

我需要在具有相同名称的某些文件中搜索并替换所有出现的未知字符。

用vi打开此类文件,我读取了该字符的<91>代码。用nano打开它们,我在钻石(黑色隆隆声)中看到一个“问号”。

我想用引号(')代替这样的未知字符。我正在尝试许多运气不佳的方法。

我试过了:

find ./ -name filename.txt -exec perl -i~ -pe "s/\x91/'/" {} \;



find ./ -name filename.txt -exec sed -i "s/\x91/'/g" {} \;

编辑 有关该字符的更多信息:

Hexadecimal: 91 68 74 74
Decimal: 145 104 116 116
Octal: 221 150 164 164
Binary: 10010001 01101000 01110100 01110100

LC_ALL=C sed -n l < file

\221

如果您需要更多,请询问!


以何种方式确实sed -i "s/\x91/'/g"file不工作?
斯特凡Chazelas

Answers:


3

您应该使用一下,hexdump -C然后找到它周围的字节。假设使用UTF-8,则vi显示为<91>(十进制145,一个在文本中无意义的unicode点)将是两个字节,即0xc2和0x91。

这意味着您的替换根本不起作用,但是如果您所做的只是将0x91替换为0x27,那么您将使UTF-8无效(两个字节序列的第二个字节始终设置为高位,即> = 0x80)。这可能会使您的分析复杂化,尽管vi随后应将其显示为?'

也就是说,我对此进行了测试,并且可以正常工作:

#!/usr/bin/perl
use strict;
use warnings FATAL => qw(all);

my $data = "";
my $file = $ARGV[0];

while (<>) {
    s/\xc2\x91/'/g;
    $data .= $_;
}

open my $out, '>', $file || die "Could not write $file.";
print $out $data;
close $out;  

如果$ARGV[0]<>引用时存在,perl会将其从参数堆栈中弹出,并将其作为文件路径用于输入(我发现短脚本比一个衬板(BTW)更易于调整和使用)。这会在内存中累积(只要文件不大就可以了),而perl -i重命名原始文件以避免就地编辑竞争条件(请参阅参考资料perldoc perlrun)。

因此,您可以使用:

  find . -name "*.txt" -exec whatever.pl {} +

它不起作用,问号仍然存在...
茉莉花

您是否签入过帐hexdump -C以查看实际内容?
goldilocks 2014年

3

如果确实是字符U + 0091(UTF-8编码为0xc2 0x91)而不是字节0x91,则:

PERLIO=:utf8 perl -pi -e "s/\N{U+0091}/'/g" file

将其转换为'

使用GNU sed

sed -i "s/\xc2\x91/'/" file

编辑:

但是,根据您的情况,该文件不在UTF-8中。UTF-8字符是一个字节,仅用于ASCII字符(值0至0x7F)。其他字符由两个或多个字节表示,其值大于0x7F。因此0x91,在utf-8文件中找不到一个字节,其周围的字节不大于0x7F。

您的文件更有可能是单字节字符集,最有可能是Microsoft的一个字符集,例如Windows-1252

在Windows-1252中,0x91是左单引号字​​符。等效的Unicode是U + 2018,它以UTF-8编写0xe2 0x80 0x98

如果要将文件转换为UTF-8,最好的方法是使用专用工具。喜欢:

recode windows-1252..utf8 < file

要么:

iconv -f windows-1252 -t utf-8 < file

或者,如果您想对每个对象都这样做filename.txt

find . -type f -name filename.txt -exec sh -Cc '
  for file do
    mv "$file" "$file~" &&
      iconv -f windows-1252 -t utf-8 < "$file~" > "$file"
  done' sh {} +

它不起作用,问号仍然存在...
茉莉花

@jasmines那不是U+0091。请将输出添加LC_ALL=C sed -n l < file到问题中。
斯特凡Chazelas


我无法转换,因为不是单个文件...我需要批处理并以递归方式搜索和替换。
茉莉花2014年
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.