FMTEYEWTK о необычных регулярных выражениях
Хорошо, я собираюсь перейти от простого к возвышенному. Наслаждайтесь!
Простое решение /// e
Учитывая это:
#!/usr/bin/perl
$_ = <<"End_of_G&S";
This particularly rapid,
unintelligible patter
isn't generally heard,
and if it is it doesn't matter!
End_of_G&S
my $count = 0;
Тогда это:
s{
\b ( [\w']+ ) \b
}{
sprintf "(%s)[%d]", $1, ++$count;
}gsex;
производит это
(This)[1] (particularly)[2] (rapid)[3],
(unintelligible)[4] (patter)[5]
(isn't)[6] (generally)[7] (heard)[8],
(and)[9] (if)[10] (it)[11] (is)[12] (it)[13] (doesn't)[14] (matter)[15]!
Интерполированный код в решении Anon Array
Тогда как это:
s/\b([\w']+)\b/#@{[++$count]}=$1/g;
производит это:
#1=This #2=particularly #3=rapid,
#4=unintelligible #5=patter
#6=isn't #7=generally #8=heard,
#9=and #10=if #11=it #12=is #13=it #14=doesn't #15=matter!
Решение с кодом в LHS вместо RHS
Это помещает приращение в сам матч:
s/ \b ( [\w']+ ) \b (?{ $count++ }) /#$count=$1/gx;
дает это:
#1=This #2=particularly #3=rapid,
#4=unintelligible #5=patter
#6=isn't #7=generally #8=heard,
#9=and #10=if #11=it #12=is #13=it #14=doesn't #15=matter!
A Заикание Решение заикания Решение Решение
Это
s{ \b ( [\w'] + ) \b }
{ join " " => ($1) x ++$count }gsex;
генерирует этот восхитительный ответ:
This particularly particularly rapid rapid rapid,
unintelligible unintelligible unintelligible unintelligible patter patter patter patter patter
isn't isn't isn't isn't isn't isn't generally generally generally generally generally generally generally heard heard heard heard heard heard heard heard,
and and and and and and and and and if if if if if if if if if if it it it it it it it it it it it is is is is is is is is is is is is it it it it it it it it it it it it it doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't doesn't matter matter matter matter matter matter matter matter matter matter matter matter matter matter matter!
Изучение границ
Существуют более надежные подходы к границам слов, которые работают для множественных притяжений (предыдущие подходы этого не делают), но я подозреваю, что ваша загадка заключается в том, чтобы заставить ++$count
выстрелить, а не в тонкостях поведения \b
.
Я действительно хотел бы, чтобы люди поняли, что \b
не то, что они думают.
Они всегда думают, что это означает, что есть пробел или край строки
там. Они никогда не думают об этом как о \w\W
или \W\w
переходах.
# same as using a \b before:
(?(?=\w) (?<!\w) | (?<!\W) )
# same as using a \b after:
(?(?<=\w) (?!\w) | (?!\W) )
Как видите, это зависит от того, к чему это относится. Для этого и используется предложение (?(COND)THEN|ELSE)
.
Это становится проблемой с такими вещами, как:
$_ = qq('Tis Paul's parents' summer-house, isn't it?\n);
my $count = 0;
s{
(?(?=[\-\w']) (?<![\-\w']) | (?<![^\-\w']) )
( [\-\w'] + )
(?(?<=[\-\w']) (?![\-\w']) | (?![^\-\w']) )
}{
sprintf "(%s)[%d]", $1, ++$count
}gsex;
print;
, который правильно печатает
('Tis)[1] (Paul's)[2] (parents')[3] (summer-house)[4], (isn't)[5] (it)[6]?
Беспокоясь о Unicode
ASCII в стиле 1960-х годов устарел примерно на 50 лет. Точно так же, как всякий раз, когда вы видите, что кто-то пишет [a-z]
, это почти всегда неправильно, оказывается, что такие вещи, как тире и кавычки, также не должны отображаться как литералы в шаблонах. Пока мы это делаем, вы, вероятно, не хотите использовать \w
, потому что это включает в себя также цифры и подчеркивания, а не только алфавит.
Представьте себе эту строку:
$_ = qq(\x{2019}Tis Ren\x{E9}e\x{2019}s great\x{2010}grandparents\x{2019} summer\x{2010}house, isn\x{2019}t it?\n);
который вы могли бы иметь как литерал с use utf8
:
use utf8;
$_ = qq(’Tis Renée’s great‐grandparents’ summer‐house, isn’t it?\n);
На этот раз я пойду по шаблону немного по-другому, отделяя свое определение терминов от их исполнения, чтобы попытаться сделать его более читабельным и, следовательно, более удобным:
#!/usr/bin/perl -l
use 5.10.0;
use utf8;
use open qw< :std :utf8 >;
use strict;
use warnings qw< FATAL all >;
use autodie;
$_ = q(’Tis Renée’s great‐grandparents’ summer‐house, isn’t it?);
my $count = 0;
s{ (?<WORD> (?&full_word) )
# the rest is just definition
(?(DEFINE)
(?<word_char> [\p{Alphabetic}\p{Quotation_Mark}] )
(?<full_word>
# next line won't compile cause
# fears variable-width lookbehind
#### (?<! (?&word_char) ) )
# so must inline it
(?<! [\p{Alphabetic}\p{Quotation_Mark}] )
(?&word_char)
(?:
\p{Dash}
| (?&word_char)
) *
(?! (?&word_char) )
)
) # end DEFINE declaration block
}{
sprintf "(%s)[%d]", $+{WORD}, ++$count;
}gsex;
print;
Этот код при запуске выдает:
(’Tis)[1] (Renée’s)[2] (great‐grandparents’)[3] (summer‐house)[4], (isn’t)[5] (it)[6]?
Ладно, может быть, у вас есть FMTEYEWTK о необычных регулярных выражениях , но разве вы не рады, что спросили? ☺