Perl регулярное совпадение регулярных выражений без точки

Есть много вопросов о том, как сделать многострочное регулярное выражение в Perl. Большинство из них упоминают s переключатель, который заставляет точку соответствовать новой строке. Однако я хочу сопоставить точную фразу (а не образец) и не знаю, где будут новые строки. Таким образом, вопрос заключается в следующем: можете ли вы игнорировать символы новой строки вместо того, чтобы сопоставлять их с .?

MWE:

$pattern = "Match this exact phrase across newlines";

$text1 = "Match\nthis exact\nphrase across newlines";
$text2 = "Match this\nexact phra\nse across\nnewlines";

$text3 = "Keep any newlines\nMatch this exact\nphrase across newlines\noutside\nof the match";

$text1 =~ s/$pattern/replacement text/s;
$text2 =~ s/$pattern/replacement text/s;
$text3 =~ s/$pattern/replacement text/s;

print "$text1\n---\n$text2\n---\n$text3\n";

Я могу поставить точки в шаблоне вместо пробелов ("Match.this.exact.phrase") но это не работает для второго примера. Я могу удалить все новые строки как предварительную обработку, но я хотел бы сохранить новые строки, которые не являются частью соответствия (как в третьем примере).

Желаемый результат:

replacement text
---
replacement text
---
Keep any newlines
replacement text
outside
of the match

4 ответа

Решение

Звучит так, как будто вы хотите изменить свой "точный" шаблон, чтобы он соответствовал новым строкам в любом месте, а также разрешить использование новых строк вместо пробелов. Поэтому измените ваш шаблон так:

$pattern = "Match this exact phrase across newlines";
$pattern =~ s/\S\K\B/\n?/g;
$pattern =~ s/ /[ \n]/g;

Большую часть времени вы рассматриваете переводы строк как пробелы. Если это все, что вы хотели сделать, все, что вам нужно, это

$text =~ s/\n/ /g;
$text =~ /\Q$text_to_find/    # or $text =~ /$regex_pattern_to_match/

Тогда есть один раз, когда вы хотите игнорировать это. Если это все, что вы хотели сделать, все, что вам нужно, это

$text =~ s/\n//g;
$text =~ /\Q$text_to_find/    # or $text =~ /$regex_pattern_to_match/

Выполнение того и другого практически невозможно, если у вас есть соответствующий шаблон регулярных выражений. Но вы, похоже, хотите сопоставить буквенный текст, что открывает некоторые возможности.

( my $pattern = $text_to_find )
   =~ s/(.)/ $1 eq " " ? "[ \\n]" : "\\n?" . quotemeta($1) /seg;
$pattern =~ s/^\\n\?//;
$text =~ /$pattern/

Просто замените буквенные пробелы классом символов, который соответствует пробелу или переводу строки:

$pattern = "Match[ \n]this[ \n]exact[ \n]phrase[ \n]across[ \n]newlines";

Или, если вы хотите быть более снисходительным, используйте \s или же \s+ вместо этого, так как \s также соответствует символам новой строки.

Это конечно некрасиво, но работает

M\n?a\n?t\n?c\n?h\st\n?h\n?i\n?s\se\n?x\n?a\n?ct\sp\n?h\n?r\n?a\n?s\n?e\sa\n?c\n?r\n?o\n?s\n?s\sn\n?e\n?w\n?l\n?i\n?n\n?e\n?s

Для каждой пары букв внутри слова разрешите новую строку между ними \n?, И замените каждый пробел в вашем регулярном выражении \s,

Может быть непригодным для использования, но он выполняет свою работу;)

Проверьте это на regex101.

Другие вопросы по тегам