Как я могу сохранить пробелы при сопоставлении и замене нескольких слов в Perl?
-
07-07-2019 - |
Вопрос
Допустим, у меня есть какой-то оригинальный текст:
here is some text that has a substring that I'm interested in embedded in it.
Мне нужно, чтобы текст соответствовал какой-то его части, скажем:"has a substring
".
Однако исходный текст и соответствующая строка могут иметь различия в пробелах.Например, текст соответствия может быть:
has a substring
или
has a substring
и /или исходный текст может быть:
here is some text that has a substring that I'm interested in embedded in it.
То, что мне нужно, чтобы моя программа выводила, это:
here is some text that [match starts here]has a substring[match ends here] that I'm interested in embedded in it.
Мне также нужно сохранить шаблон пробелов в оригинале и просто добавить к нему начальный и конечный маркеры.
Есть какие-нибудь идеи о способе использования регулярных выражений Perl, чтобы это произошло?Я пытался, но в итоге ужасно запутался.
Решение
Прошло некоторое время с тех пор, как я использовал регулярные выражения perl, но как насчет:
$match = s/(has\s+a\s+substring)/[$1]/ig
Это позволило бы зафиксировать ноль или более пробелов и символов новой строки между словами.Это заключит все совпадение в квадратные скобки, сохранив исходное разделение.Это не автоматически, но это действительно работает.
Вы могли бы играть с этим в игры, например, брать веревку "has a substring"
и выполняем преобразование над ним, чтобы сделать его "has\s*a\s*substring"
чтобы сделать это немного менее болезненным.
Редактировать:Включены комментарии ysth о том, что метасимвол \ s соответствует переводу строк и исправлениям Хоббса в моем использовании.
Другие советы
Этот шаблон будет соответствовать строке, которую вы хотите найти:
(has\s+a\s+substring)
Итак, когда пользователь вводит строку поиска, замените любой пробел в строке поиска на \s+
и у вас есть свой шаблон.The, просто замените каждое совпадение на [match starts here]$1[match ends here]
где $1
является совпадающим текстом.
В регулярных выражениях вы можете использовать +
означать "один или более". Итак, что-то вроде этого
/has\s+a\s+substring/
Матчи has
за которым следует один или несколько символов-пробелов, за которыми следует a
за которым следует один или несколько символов-пробелов, за которыми следует substring
.
Соединяя это с оператором подстановки, вы можете сказать:
my $str = "here is some text that has a substring that I'm interested in embedded in it.";
$str =~ s/(has\s+a\s+substring)/\[match starts here]$1\[match ends here]/gs;
print $str;
И на выходе получается:
here is some text that [match starts here]has a substring[match ends here] that I'm interested in embedded in it.
Многие предлагали, использовать \s+
чтобы соответствовать пробелам.Вот как вы делаете это автоматически:
my $original = "here is some text that has a substring that I'm interested in embedded in it.";
my $search = "has a\nsubstring";
my $re = $search;
$re =~ s/\s+/\\s+/g;
$original =~ s/\b$re\b/[match starts here]$&[match ends here]/g;
print $original;
Выходной сигнал:
here is some text that [match starts here]has a substring[match ends here] that I'm interested in embedded in it.
Возможно, вам захочется экранировать любые мета-символы в строке.Если кому-то интересно, я мог бы добавить это.
Это пример того, как вы могли бы это сделать.
#! /opt/perl/bin/perl
use strict;
use warnings;
my $submatch = "has a\nsubstring";
my $str = "
here is some
text that has
a substring that I'm interested in, embedded in it.
";
print substr_match($str, $submatch), "\n";
sub substr_match{
my($string,$match) = @_;
$match =~ s/\s+/\\s+/g;
# This isn't safe the way it is now, you will need to sanitize $match
$string =~ /\b$match\b/;
}
В настоящее время это делает все, чтобы проверить $match
переменная для небезопасных символов.