如何删除非ascii字符并在非ascii字符使用Perl单行的字段中添加空格?

时间:2014-03-27 19:11:42

标签: regex perl formatting

Hi Stack Overflow社区,

我有以下问题。

我得到了一个名为bad的文件,其中包含以下内容:

SPAM EATER       PO BOX 5555          FAKE STREET
FOO BAR          ìPO BOX 1234         LOLLERCOASTER VILLAGE
LOL MAN          PO BOX 9876          NEXT DOOR

我想从中删除非ascii字符(在第二个记录的第二列的开头),以便获得一个没有奇怪字符并且所有列都对齐的文件。此外,还有一个要求是使用 Perl one-liner 来实现这一目标 - 因此,不能使用awksed或类似的命令。我尝试了以下方法,但在第三栏中缩短了一个空格:

$ perl -plne 's/[^[:ascii:]]//g' bad > bad.clean

$ cat bad.clean
SPAM EATER       PO BOX 5555          FAKE STREET
FOO BAR          PO BOX 1234         LOLLERCOASTER VILLAGE
LOL MAN          PO BOX 9876          NEXT DOOR

我也尝试使用相同的单行,但这次用空格替换非ascii字符。在这种情况下,记录最后在第二列中有两个额外的空格,在第三列中有一个额外的空格:

$ perl -plne 's/[^[:ascii:]]/ /g' bad > bad.clean.space

$ cat bad.clean.space
SPAM EATER       PO BOX 5555          FAKE STREET
FOO BAR            PO BOX 1234         LOLLERCOASTER VILLAGE
LOL MAN          PO BOX 9876          NEXT DOOR

不知何故,非ascii字符似乎占用2个字节而不是一个 - 这是正确的,还是我错过了什么?

预期的输出是:

SPAM EATER       PO BOX 5555          FAKE STREET
FOO BAR          PO BOX 1234          LOLLERCOASTER VILLAGE
LOL MAN          PO BOX 9876          NEXT DOOR

有没有办法,使用Perl单行程序来获得预期的结果?我想到了一种方法,在删除非ascii字符后添加一个空格,在已经进行更改的字段中,但我找不到这样做的方法。此外,非ascii字符可以出现在任何字段上,而不仅仅出现在第二个字段中。

顺便说一下,一些可能有用的信息:这是一台运行AIX的{​​{1}}计算机。

谢谢!


编辑:

由于@ThisSuitIsBlack没有提到,有两个非ascii字符。因此,我想我只想在该字段的末尾添加一个空格,如果至少一个非ascii字符被命令删除。 有没有办法让这个额外的空间包含在同一个句子中,所以它也可以作为一个单行程来完成?


编辑:

在查看了大量数据后,我可以看出非ascii字符始终显示为成对,并且原始文件中的下一个字段(在运行单行之前)始终是右边的一个空格。其他专栏。所以,我正在更改此问题的标题以符合要求: Perl one-liner删除非ascii字符,并在非ascii字符 <的字段中添加空格/ p>

3 个答案:

答案 0 :(得分:3)

取出2个非ascii,在字段后添加一个空格 使用非ascii和3个空格作为分隔符对。

 #  s/[^[:ascii:]]{2}(.*?[ ]{3})/$1 /g

 [^[:ascii:]]{2} 
 ( .*? [ ]{3} )

Perl测试用例

$/ = undef;
$str = <DATA>;
$str =~ s/[^[:ascii:]]{2}(.*?[ ]{3})/$1 /g;
print $str;

__DATA__
SPAM EATER       PO BOX 5555          FAKE STREET
FOO BAR          ìPO BOX 1234         LOLLERCOASTER VILLAGE
LOL MAN          PO BOX 9876          NEXT DOOR

输出&gt;&gt;

SPAM EATER       PO BOX 5555          FAKE STREET
FOO BAR          PO BOX 1234          LOLLERCOASTER VILLAGE
LOL MAN          PO BOX 9876          NEXT DOOR

答案 1 :(得分:2)

您可以使用tr

tr -cs '[:print:]' ' '

这将用空格替换不可打印字符的运行。

答案 2 :(得分:1)

这可能是一个愚蠢的问题,但是:为什么不通过修改输入以使其具有正确数量的空格来对齐它?与其他行相比,输入的第二行在第二列和第三列之间具有不同数量的填充空格。

如果你必须像示例中的那样有未对齐的输入,那么这样的东西就会起作用(在示例的狭窄情况下,可以使用floor或类似的东西进行调整以适用于其他情况。但是,我不认为它会在一般情况下真正发挥作用;没有神奇的&#34;检测并纠正我的列大小&#34;功能而不使用Text::Table或类似的你的oneliner):

perl -plne 's/([^[:ascii:]]+?)((?:\w+\s)+?)(\s+?.+)/$2 . (" " x (int(length($1) \/ 2) - 1)) . $3/ge' bad > bad.clean

这完全没有优化,可能效率低下。一个真正的正则表达式大师可能会把它折叠成一些字节。但是,它应该指向正确的方向(即使用右侧部分中的函数,而不是静态值)。它也只有在双字节字符的约束是字符串中唯一的非ASCII值的情况下才能工作。尽管如此,这是一个经常错误的假设。在编写另一行代码之前,请先阅读this excellent article by Joel Spolsky;每个必须参与角色编码的人都应该了解基础知识。