Соответствующие * последовательные * строки, начинающиеся с произвольного количества пробелов, за которыми следует символ
Я пытаюсь сопоставить последовательные строки, начинающиеся с произвольного количества пробела, за которым следует символ |
, Я использую s
флаг, чтобы .
соответствует новым строкам
То, что у меня есть, до сих пор работает с ограниченным количеством пробелов |
,
У меня проблемы с той частью, которая определяет, что достигнута линия, которая не соответствует требованиям. По какой-то причине \n\s*[^\|]
не делает трюк. Что я сейчас делаю, так это следующее:
(?P<terminating>
\n( # when newline is encountered...
[^\|\s] # check if next character is not: (| or space)
|
[\s][^\|\s] # check if next characters are not: space + (| or space)
|
[\s][\s][^\|\s] # check if next characters are not: space + space + (| or space)... And so on....
)
|
$
)
Это очевидно работает только для двух пробелов. Я хотел бы сделать эту работу для произвольного количества пробелов. Я посмотрел на рекурсию, но, похоже, в этом случае это довольно тяжелое оружие. Вот теперь мой вопрос: почему \n\s*[^\|]
не работает, и есть ли другой способ решить это без рекурсии?
Ниже приведен пример ввода и полученного соответствия, которое я хотел бы получить:
Строка ввода:
Lorem ipsum dolor sit amet,
consectetur adipisicing
elit,
|sed do
|eiusmod tempor incididunt
|ut labore et dolore magna aliqua.
Ut enim ad minim veniam,
quis nostrud exercitation
ullamco laboris nisi ut
aliquip ex ea commodo consequat.
Вывод - одна строка с содержимым:
|sed do\n |eiusmod tempor incididunt\n |ut labore et dolore magna aliqua.
Я не хочу три матча с каждой из линий, которые имеют |
в этом.
4 ответа
Я решил это сам. Я предполагаю, что должен исключить пробел из группы символов, которую я исключаю:
n\s*[^\|\s]
Хотя я не совсем уверен, почему это так, я случайно наткнулся на это. Я был бы признателен, если бы кто-то мог объяснить причину этого.
Полное выражение теперь выглядит следующим образом:
'/
(?:
(^|\n)\s*\|
)
(?P<main>
.*?
)
(?=
\n\s*[^\|\s]
|
$
)
/sx'
Если вы используете PHP, это должно сделать это:
(?m)^\h*\|.*(?:\R\h*\|.*)*
Некоторые интересные места:
\h
соответствует горизонтальному пробелу, что означает пробел и символы табуляции\R
соответствует разделителю строк, будь то\n
,\r\n
, или же\r
(?m)
включает многострочный режим, который позволяет^
соответствовать началу строкиоднолинейный /DOTALL режим не установлен, потому что мы хотим
.*
остановиться в конце строки.Я никогда не пользуюсь
\s
потому что он соответствует любому символу пробела, включая пробел, табуляцию, возврат каретки (\r
) и перевод строки (\n
). Если вы просто хотите найти совпадение, которое может занимать несколько строк, можно использовать\s
или же.
в однолинейном режиме. Но эта задача включает в себя сопоставление вещей в зависимости от их положения относительно начала строки. Это гораздо проще сделать, если вы явно сопоставите различные типы пробельных символов.
Если вы используете Python \h
а также \R
Shorthands не будет работать, поэтому вам нужно быть более многословным:
(?m)^[ \t]*\|.*(?:[\r\n]+[ \t]*\|.*)*
Обратите внимание, что [\r\n]+
также будет соответствовать пустым строкам; если вы хотите убедиться, что между строками находится ровно один разделитель строк, используйте вместо этого:
(?m)^[ \t]*\|.*(?:(?:\r\n|[\r\n])[ \t]*\|.*)*
Вы можете попробовать этот шаблон без модификатора s:
(?:(?:^|(?<=\n))[^\S\r\n]*\|.*(?:\r?\n|$)?)+
Для тех, кто использует Perl, вы можете использовать приведенный ниже код. Я уверен, что это может быть лучше. Я был бы рад узнать, если кто-то может помочь мне улучшить код
my $Str = "Lorem ipsum dolor sit amet,
consectetur adipisicing
elit,
|sed do
|eiusmod tempor incididunt
|ut labore et dolore magna aliqua.
Ut enim ad minim veniam,
quis nostrud exercitation
ullamco laboris nisi ut
aliquip ex ea commodo consequat.";
@lLine = split('\n', $Str);
foreach $lLine (@lLine) {
if($lLine =~ /^[\s\|]+.*$/) {
$ReturnStr .= $lLine;
}
}
Выходные данные были следующими: "Sed do |eiusmod tempor incididunt" |ut labore et dolore magna aliqua.