Perl REGEXP如何从没有备用模式的单词中匹配子字符串?
大家下午好 我有一串空格分隔的单词。我需要从字符串中找到与字母数字模式匹配的单词,部分或整个单词。 我需要只由字母数字字符组成的单词 为了使我的目的更清楚,我有以下条件: “foo bar quux foo foo bar foo quux barfoo Barbor Barqux”。 “quuxfoo quuxbar Quuxqux[foo]foo{foo}foo barfoo”。 “quuxfoo foo 2foo 2bar foo 2Quux foo 2foo bar2foo quux2foo 2foo 2foo” 我想找到所有的单词,每个单词里面只有一次'foo',而不是那些带有特殊字符的单词,比如[foo],{foo} 我用Perl中的以下代码完成了这项工作:Perl REGEXP如何从没有备用模式的单词中匹配子字符串?,regex,perl,Regex,Perl,大家下午好 我有一串空格分隔的单词。我需要从字符串中找到与字母数字模式匹配的单词,部分或整个单词。 我需要只由字母数字字符组成的单词 为了使我的目的更清楚,我有以下条件: “foo bar quux foo foo bar foo quux barfoo Barbor Barqux”。 “quuxfoo quuxbar Quuxqux[foo]foo{foo}foo barfoo”。 “quuxfoo foo 2foo 2bar foo 2Quux foo 2foo bar2foo quux2f
my $s=
'foo bar quux foofoo foobar fooquux barfoo barbar barquux quuxfoo quuxbar quuxquux ' .
'[foo] (foo) {foo} foofoo barfoo quuxfoo foo2foo foo2bar foo2quux foo2foo bar2foo quux2foo';
my @m = ($s=~/(\w+foo|foo\w+|^foo|foo$)/g) ;
say "@m";
say "Number of sub-strings matching the pattern: ", scalar @m;
print( sprintf("%02d: ",$_),
($s=~/(\w+foo|foo\w+|^foo|foo$)/g)[$_],
qq(\n) )
for (0..@m-1);
我得到了我想要的结果:
foo foofoo foobar fooquux barfoo quuxfoo foofoo barfoo quuxfoo foo2foo foo2bar foo2quux foo2foo bar2foo quux2foo
Number of sub-strings matching the pattern: 15
00: foo
01: foofoo
02: foobar
03: fooquux
04: barfoo
05: quuxfoo
06: foofoo
07: barfoo
08: quuxfoo
09: foo2foo
10: foo2bar
11: foo2quux
12: foo2foo
13: bar2foo
14: quux2foo
但是,如果我需要并且愿意在更复杂的字符串中添加更多的模式来搜索,它很快就会变得混乱,我会对交替模式“|”的连续性感到困惑
是否有人帮助我编写一个更短/更清晰的模式regexp,以一种可以用一种模式编写的方式来分隔“foo”或任何其他单词/子单词
先谢谢你
通用汽车
W7/64上的草莓5.022,但我认为它对于5.016甚至5.008以上的任何Perl都是相当通用的
我发现道格和斯特芬的解决方案太适合我了。grep不是最具可读性的,它更符合我的Perl水平,但我认为,作为基于纯regexp的,它更能够处理未来的单词添加,并且具有单词限制
处理
我想在这里写下我对它的理解,以便在我打算根据我的实际需要扩展它之前,如果我错了,你可以纠正我
(?: # You start a non capturing group.
(?<= # You start a lookbehind (so non capturing BY NATURE, am I right ?, because
# if not, as it is being enclosed in round-brackets '()' it restarts to be
# capturing even inside a non capturing group, isn't it?)
\h # In the lookbehind you look for an horizontal space (could \s have been used
# there?)
^ # in the non capturing group but outside of the lookbehind you look for the
# start of string anchor. Must not be present in the lookbehind group because
# it requires a same length pattern size and ^ has length==0 while \h is
# non zero.
\w*foo\w* # You look for foo within an alphanum word. No pb to have '*' rather than '+'
# because your left (and right, that we'll see it down) bound has been well
# restricted.
(?= # You start a lookforward pattern (non capturing by nature here again, right?),
# to look for:
\h or $ # horiz space or end of string anchor. However the lookaround size is
# different here as $ is still 0 length (as ^ anchor) and \h still non
# zero. "AND YET IT MOVES" (I tested your regexp and it worked) because
# only the lookbehind has the 'same-size' pattern restriction, right?
谢谢你们的帮助,各位,在最后一点之后,我不再用我的小问题来烦你们了,并考虑我的问题得到了完全的回答。
G.可能先过滤不需要的单词,然后对过滤后的单词使用grep:
use strict;
use warnings;
my $s=
'foo bar quux foofoo foobar fooquux barfoo barbar barquux quuxfoo quuxbar quuxquux ' .
'[foo] (foo) {foo} foofoo barfoo quuxfoo foo2foo foo2bar foo2quux foo2foo bar2foo quux2foo';
my @words = ( $s=~/(?:(?<=\h)|^)(\w+)(?=\h|$)/g );
my @foos = grep(/foo/, @words);
while (my ($i, $v) = each @foos) {
printf "%02d: %s\n", $i,$v;
}
或者,您可以组合对按水平空格分割的单词列表进行过滤,并测试生成的单词是否全部为字母数字:
@foos=grep {/foo/ && /^\w+$/} split /\h/, $s; # same result
或者
或者,在以下情况下:
根据评论中的要求,包括:
$s=~/(?:(?<=\h)|^)(\w*foo\w*)(?=\h|$)/g
(?:(?<=\h)|^) Assert either after a \h (horizontal space) or at start of line ^
(\w*foo\w*) Capture a 'word' with 'foo' and only \w characters (or, [a-zA-Z0-9_] characters)
(?=\h|$) Assert before either a \h horizontal space or end of line $
唯一棘手的部分是?:?可能先过滤不需要的单词,然后对过滤后的单词使用grep:
use strict;
use warnings;
my $s=
'foo bar quux foofoo foobar fooquux barfoo barbar barquux quuxfoo quuxbar quuxquux ' .
'[foo] (foo) {foo} foofoo barfoo quuxfoo foo2foo foo2bar foo2quux foo2foo bar2foo quux2foo';
my @words = ( $s=~/(?:(?<=\h)|^)(\w+)(?=\h|$)/g );
my @foos = grep(/foo/, @words);
while (my ($i, $v) = each @foos) {
printf "%02d: %s\n", $i,$v;
}
或者,您可以组合对按水平空格分割的单词列表进行过滤,并测试生成的单词是否全部为字母数字:
@foos=grep {/foo/ && /^\w+$/} split /\h/, $s; # same result
或者
或者,在以下情况下:
根据评论中的要求,包括:
$s=~/(?:(?<=\h)|^)(\w*foo\w*)(?=\h|$)/g
(?:(?<=\h)|^) Assert either after a \h (horizontal space) or at start of line ^
(\w*foo\w*) Capture a 'word' with 'foo' and only \w characters (or, [a-zA-Z0-9_] characters)
(?=\h|$) Assert before either a \h horizontal space or end of line $
唯一棘手的部分是?:?这取决于:如果你想从foobar获得foobar,那很容易。您只需将foo与前后可选的单词字符进行匹配,然后在两侧匹配一个单词边界\b,该边界可以是输入的开头或一些非单词字符:
my @m = ($s=~/(\b\w*foo\w*\b)/g);
print( sprintf("%02d: ",$_),
($s=~/(\b\w*foo\w*\b)/g)[$_],
qq(\n) )
for (0..@m-1);
输出:
00: foo
01: foofoo
02: foobar
03: fooquux
04: barfoo
05: quuxfoo
06: foo
07: foo
08: foo
09: foofoo
10: barfoo
11: quuxfoo
12: foo2foo
13: foo2bar
14: foo2quux
15: foo2foo
16: bar2foo
17: quux2foo
如果没有,那就有点难了。在这里,我将匹配输入的开头或空格,然后用可选的单词字符包围foo,然后我们需要一个零长度断言,它需要一个空格或输入的结尾:
my @m = ($s=~/(?:^|\s)(\w*foo\w*)(?=\s|$)/g);
print( sprintf("%02d: ",$_),
($s=~/(?:^|\s)(\w*foo\w*)(?=\s|$)/g)[$_],
qq(\n) )
for (0..@m-1);
输出:
00: foo
01: foofoo
02: foobar
03: fooquux
04: barfoo
05: quuxfoo
06: foofoo
07: barfoo
08: quuxfoo
09: foo2foo
10: foo2bar
11: foo2quux
12: foo2foo
13: bar2foo
14: quux2foo
这取决于:如果你想从foobar那里得到foobar,那很容易。您只需将foo与前后可选的单词字符进行匹配,然后在两侧匹配一个单词边界\b,该边界可以是输入的开头或一些非单词字符:
my @m = ($s=~/(\b\w*foo\w*\b)/g);
print( sprintf("%02d: ",$_),
($s=~/(\b\w*foo\w*\b)/g)[$_],
qq(\n) )
for (0..@m-1);
输出:
00: foo
01: foofoo
02: foobar
03: fooquux
04: barfoo
05: quuxfoo
06: foo
07: foo
08: foo
09: foofoo
10: barfoo
11: quuxfoo
12: foo2foo
13: foo2bar
14: foo2quux
15: foo2foo
16: bar2foo
17: quux2foo
如果没有,那就有点难了。在这里,我将匹配输入的开头或空格,然后用可选的单词字符包围foo,然后我们需要一个零长度断言,它需要一个空格或输入的结尾:
my @m = ($s=~/(?:^|\s)(\w*foo\w*)(?=\s|$)/g);
print( sprintf("%02d: ",$_),
($s=~/(?:^|\s)(\w*foo\w*)(?=\s|$)/g)[$_],
qq(\n) )
for (0..@m-1);
输出:
00: foo
01: foofoo
02: foobar
03: fooquux
04: barfoo
05: quuxfoo
06: foofoo
07: barfoo
08: quuxfoo
09: foo2foo
10: foo2bar
11: foo2quux
12: foo2foo
13: bar2foo
14: quux2foo
您可以拆分字符串并筛选数组:
use strict;
use warnings;
my $s=
'foo bar quux foofoo foobar fooquux barfoo barbar barquux quuxfoo quuxbar quuxquux ' .
'[foo] (foo) {foo} foofoo barfoo quuxfoo foo2foo foo2bar foo2quux foo2foo bar2foo quux2foo';
my @res = grep {/foo/ && !/\W/} split /\s/, $s;
print join(" ", @res);
您可以拆分字符串并筛选数组:
use strict;
use warnings;
my $s=
'foo bar quux foofoo foobar fooquux barfoo barbar barquux quuxfoo quuxbar quuxquux ' .
'[foo] (foo) {foo} foofoo barfoo quuxfoo foo2foo foo2bar foo2quux foo2foo bar2foo quux2foo';
my @res = grep {/foo/ && !/\W/} split /\s/, $s;
print join(" ", @res);
你是想从foobar那里得到foobar,还是根本不应该得到那场比赛?@steffen:不,你是对的,我不想有foo或[foo]或{foo}或;傅;,等等,嘿,把第二部分移到一个新的答案,接受它;你是想从foobar那里得到foobar,还是根本不应该得到那场比赛?@steffen:不,你是对的,我不想有foo或[foo]或{foo}或;傅;,等等,嘿,把第二部分移到一个新的答案,接受它;为了排除单词前面或后面的so parens作为单词边界,我发现在变量中的第一个示例中使用qr更清楚地创建您自己的单词边界[^…]为了排除单词前面或后面的so parens作为单词边界,我发现更清楚地创建您自己的单词边界[^…]在第一个例子中,在一个带有qr的变量中,这是正确的方向。保持简单。请记住,正则表达式使用的“单词字符”的定义是字母、数字和下划线,因此,如果您有更具体的要求,您可能需要构造一个新的字符。很好!谢谢我不是第一眼就明白的。现在我想我更明白了。我不会在regexps中使用它取得进展,但它会立即解决我的pb问题。我在快速解决和学习之间保持平衡。我会尽量做到两个。真的,正如佩尔大师所说,有不止一种方法可以做到这一点。这是正确的方向。保持简单。记住
正则表达式使用的“单词字符”的定义是字母、数字和下划线,因此如果您有更具体的要求,您可能需要构造一个!谢谢我不是第一眼就明白的。现在我想我更明白了。我不会在regexps中使用它取得进展,但它会立即解决我的pb问题。我在快速解决和学习之间保持平衡。我会尽量做到两个。真的,正如佩尔大师所说,有不止一种方法可以做到这一点。谢谢@foos=$s=~/?:?@GillesMaisonneuve:添加了解释。谢谢@foos=$s=~/?:?@GillesMaisonneuve:添加了解释。