Добрый день всем,
У меня есть строка пустых разделенных слов.Мне нужно найти слова из этой строки, которые соответствуют буквенно-цифровому шаблону, частичному или целому слову.Мне нужны слова, состоящие только из буквенно-цифровых символов.
Чтобы прояснить мою цель, у меня есть строка:
'foo bar quux foofoo foobar fooquux barfoo barbar barquux'.
'quuxfoo quuxbar quuxquux [foo] (foo) {foo} foofoo barfoo'.
'quuxfoo foo2foo foo2bar foo2quux foo2foo bar2foo quux2foo'
, и я хочу найти все слова с 'foo' внутри (только один раз за слово), но не те, у которых есть специальные символы (не альфа), например"[foo]", "{foo}" ...
Я сделал это со следующим фрагментом кода в Perl:
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
Но если мне нужно (и я буду) добавлять больше шаблонов для поиска в более сложной строке, это быстро становится грязным, и я путаюсь с последовательностью альтернативных шаблонов ('|').
Есть ли кто-нибудь, кто мог бы помочь мне написать более короткое / более чистое регулярное выражение шаблона, чтобы разделить слово / подслово 'foo' (или любое другое) так, чтобы его можно было записать одним шаблоном?
Заранее спасибо.
GM
Strawberry 5.022 на W7 / 64, но я думаю, что это довольно универсально для любого Perl выше 5.016 или даже 5.008;
Я нашел решение Дауг (и Штеффен тоже) подходящим для меня.Не самый читабельный, grep больше соответствует моему уровню Perl, но я думаю, что, основываясь исключительно на регулярном выражении, он способен обрабатывать добавление слов в будущем с помощью обработки пределов слов .
$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 $
Я хотел бы записать здесь, что я понял, чтобы вы могли исправить меня, если я ошибаюсь, прежде чем я собираюсь расширить его для моих реальных потребностей.
(?: # 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?
СпасибоЗа вашу помощь, все вы, после этого последнего пункта я не буду больше беспокоить вас своими маленькими проблемами и считаю, что мой вопрос полностью отвечен.Г.