2012-01-19 51 views
8

考虑一个文本文件与内容:perl可以用自己的替代词一次代替多个关键词吗?

apple apple pear plum apple cherry pear apple 
cherry plum plum pear apple cherry pear pear apple plum 

,并考虑Perl的一行代码:

perl -pe "s/apple/green/g and s/pear/yellow/g and s/plum/blue/g and s/cherry/red/g" < fruits.txt 

这将替换所有的水果,它的颜色。
现在,这可以以某种方式在单个s /// g中完成,而不是上述四个?

我也关心水果单词的顺序。
如果我的示例不包含“苹果”,则其他替代品都不会完成。 我该如何解决这个问题?

请注意:我想保留解决方案为一行。
因此,定义哈希,读取文件和其他需要许多perl代码行的解决方案不会带我前进。

这更多的是好奇心,而不是项目依赖的生死攸关的问题。 现在只是困扰了我一段时间,并认为一个更有经验的perl用户可以帮助解决问题,或者让我摆脱自己的苦难,直接告诉我,这不能以perl的方式完成我想要的方式。

+0

我觉得原来的更为清晰可辨,但要注意的是,行为比建议的解决方案,如果任何模式或字符串的是其他模式或字符串子不同(连续换人vs一次传球) –

回答

4
perl -E 'my %h = qw(apple green foo bar); say "apple foo" =~ s/(apple|foo)/$h{$1}/rge;' 
+0

这是我以后的答案。关键是$ h {$ 1}表单,谢谢指出,ruz!我必须承认,mkb和ikegami提供了一个更完整的解决方案,我会实际使用他们建议的内容,但我会将这个答案标记为胜利者,因为它包含我错过的关键。 – Keve

5

perl -pe '%a=qw(apple green pear yellow plum blue cherry red);$b=join("|",keys %a);s/($b)/$a{$1}/g' < fruits.txt

+0

我知道你说没有哈希,但它仍然是一条线。 – mkb

+0

假设字符串是事先已知的,你可以使用hashref文字作为替换表达式的一部分? – Neil

+0

谁降低了这个?这是非常优雅的,仍然可以作为单线使用。 –

11

替换

perl -pe's/apple/green/g and s/pear/yellow/g and ...' fruits.txt 

perl -pe's/apple/green/g; s/pear/yellow/g; ...' fruits.txt 

更快并且不具有一个问题,其中a => B B => C:

perl -pe' 
    BEGIN { 
     %subs=qw(apple green pear yellow plum blue cherry red); 
     $re=join "|", map quotemeta, keys %subs; 
     $re = qr/$re/; 
    } 
    s/($re)/$subs{$1}/g; 
' fruits.txt 

(您可以删除« map quotemeta, »,如果你输入包含没什么特别的。)

(您可以删除换行符我添加了可读性。)

+0

优秀的解决方案。我花了相当长的一段时间才完全理解第一条$ re = ...线条的确切含义,但它非常值得。你给了我想法,我的原始要求是什么,指出了我后来可能遇到的问题。这是我收到的最全面的解决方案。我希望你不介意我接受鲁兹的回答!加分对他更有用,比对你更有用。 – Keve

+0

@Keve,谢谢,没问题:) – ikegami

1

根据不同的问题,我想我会只是有点马虎,看看每一个非空白的运行。如果它是有趣的东西,我把它取代。如果不是,我把相同的文字放回去。

$ perl5.14.2 -nE 'print s/(\S+)/$h{$1}?$h{$1}:$1/rge}BEGIN{%h=qw(apple green pear yellow plum blue cherry red)' 

如果问题是任何复杂多了,我的一行将如下所示:

$ perl fruits2color 

其他几个答案通过连接串位了正则表达式。在一个非单线程程序中,我可能会用Regex::AssembleRegexp::Trie这样的方法来做到这一点。这些模块可以构建高效的变更。

+0

我对你的替换字符串技巧印象深刻,Brian!我非常喜欢这个。但是你的大括号没有正确放置。我认为“/ rge”和“BEGIN”之间的结尾是属于最后,在“红色”之后,但在单引号之前。您可能将BEGIN块从前面移到后面。 ;-) – Keve

+1

不,那些大括号是在正确的地方。有两个隐藏的 - 你没有看到的。你尝试过单线吗? –

+0

你说得对。其实,双倍如此。因为-n,隐藏的括号在那里,不,我没有尝试之前打开我的嘴。对于那个很抱歉! – Keve

0

谁说哈希不记得他们的顺序:)?

How can I make my hash remember the order I put elements into it?

使用Tie::IxHash从 CPAN。

use Tie::IxHash; 
tie my %myhash, 'Tie::IxHash'; 

for (my $i=0; $i<20; $i++) { 
    $myhash{$i} = 2*$i; 
} 

my @keys = keys %myhash; 
# @keys = (0,1,2,3,...) 

$ perl -MTie::IxHash -pe ' 
     BEGIN { tie %h, "Tie::IxHash"; 
       %h = qw< apple green pear yellow >; 
       } 
     s<($_)>/$h{$1}/g for keys %h; 
     ' file