我有一句话:
Jon Favreau, Stan Lee, Justin Theroux, Robert Downey Jr. (Tony Stark) Gwyneth Paltrow (Pepper Potts) Don Cheadle (James Rhodes)
我想用逗号拆分行,并用该结果括起来:
Jon Favreau
Stan Lee
Justin Theroux
Robert Downey Jr. (Tony Stark)
Gwyneth Paltrow (Pepper Potts)
Don Cheadle (James Rhodes)
编辑:特殊情况
专栏:Jon Favreau,Stan Lee,Justin Theroux,Robert Downey(Jr。)(Tony Stark)Gwyneth Paltrow(Pepper Potts)Don Cheadle(James Rhodes)
世界(Jr.)在brakets。输出:
Jon Favreau
Stan Lee
Justin Theroux
Robert Downey (Jr.) (Tony Stark)
Gwyneth Paltrow (Pepper Potts)
Don Cheadle (James Rhodes)
答案 0 :(得分:6)
使用split
时,您决定是否丢弃分隔符或保留分隔符。在您的情况下,您希望保留一个分隔符(右括号)并丢弃另一个分隔符(逗号)。此外,您可能希望丢弃这些分隔符后的任何空格。
分隔符可以通过以下方式保存:
将split
模式包含在捕获括号中。在这种情况下,分隔符本身最终将作为单独的字符串,散布在您的结果中,这不是您想要的。
在零宽度断言中指定分隔符(后视,前瞻等)。这会从匹配的字符串中排除分隔符,从而防止它被丢弃。
第二种方法适用于你。
my @actors = split /(?<=\)) *|, */, $line;
要处理编辑过的问题中更复杂的场景,例如“Robert Downey(Jr。)(Tony Stark)”,您可以添加另一个零宽度断言:
my $actor_regex = qr'
(?<= \) ) # Look-behind: close paren.
\s*
(?! \s* \( ) # Negative look-ahead: opening paren.
|
, \s* # Or the other delimiter.
'x;
my @items = split $actor_regex, $line;
答案 1 :(得分:3)
首先在每个)
之后添加一个逗号,然后拆分(并丢弃)逗号:
perl -e '$_="Jon Favreau, ...";s/\)/\),/g;split ",";foreach (@_) {s/^\ //;print "$_\n"}'
收率:
Jon Favreau
Stan Lee
Justin Theroux
Robert Downey Jr. (Tony Stark)
Gwyneth Paltrow (Pepper Potts)
Don Cheadle (James Rhodes)
答案 2 :(得分:2)
归功于Randal Schwartz的一个有用的经验法则是当你知道要扔掉什么时使用split
或m//
当你知道要保留什么时使用括号。然而,将它应用于您的问题有点棘手,因为您想要同时执行这两项操作。那就是
下面的程序使用m//
并捕获,因此它根据保持的内容来定义问题。当然,最后)
很容易。为了使逗号保持在捕获缓冲区之外,代码使用正look-ahead assertion:捕获应该停留在之前之前的字符上。
容易错过的可能性也应该允许名称在字符串结尾处终止。说Stan Lee是姓,而不是第二个。如果没有$
替代方案,斯坦就会被排除在外。
代码使用DEFINE
并命名子模式来帮助读者理解正则表达式。这种方法的缺点是它会生成额外的捕获缓冲区,因此您必须使用循环而不是@names = /$name_pattern/g
。
如上所述,它接受的语言略大于您在问题中指定的语言即,它允许并丢弃两个同时具有字符名称的演员之间的逗号。
#! /usr/bin/env perl
use warnings;
use strict;
*ARGV = *DATA; # for demo only
my $name_pattern = qr/
( # capture into $1
(?&name) (?: (?&comma_terminated) | \) | $ )
)
# discard trailing whitespace and optional comma
(?: \s* (?: , \s*)? )
(?(DEFINE)
(?<name> .+? )
(?<comma_terminated> (?= ,) )
)
/x;
while (<>) {
my @names;
push @names, $1 while /$name_pattern/gx;
print "[$_]\n" for @names;
}
__DATA__
Jon Favreau, Stan Lee, Justin Theroux, Robert Downey Jr. (Tony Stark) Gwyneth Paltrow (Pepper Potts) Don Cheadle (James Rhodes) foo
输出:
[Jon Favreau] [Stan Lee] [Justin Theroux] [Robert Downey Jr. (Tony Stark)] [Gwyneth Paltrow (Pepper Potts)] [Don Cheadle (James Rhodes)] [foo]
答案 3 :(得分:1)
这样做的一种方法可能是:
my @items = split(/(\)|,)/, $line);
如果你打印出那个列表,你会得到类似的东西:
Jon Favreau
,
Stan Lee
,
Justin Theroux
,
Robert Downey Jr. (Tony Stark
)
Gwyneth Paltrow (Pepper Potts
)
Don Cheadle (James Rhodes
)
然后您需要的是重新组合单个项目,这些项目位于该列表中所有偶数位置。
答案 4 :(得分:1)
Mat已经到了现场,我刚刚在我的版本中添加了一些清洁工具:
my $names =
"Jon Favreau, Stan Lee, Justin Theroux, Robert Downey Jr. (Tony Stark) Gwyneth Paltrow (Pepper Potts) Don Cheadle (James Rhodes)";
my @names = split( /[,|\)]/, $names );
foreach my $name (@names) {
$name = $name . ")" if $name =~ /.*\(.*/;
$name =~ s/^ //;
}