Regex: захват нескольких экземпляров в одной группе слов - PullRequest
1 голос
/ 14 июля 2020

Я плохо разбираюсь в Regex и пытаюсь уже несколько часов, поэтому надеюсь, что вы мне поможете. У меня есть этот текст:

✝his is *✝he* *in✝erne✝*

Мне нужно захватить (используя PREG_OFFSET_CAPTURE) только ✝ в слове, окруженном *, поэтому мне нужно захватить только последние три ✝ в этом пример. Выходной массив должен выглядеть примерно так:

    [0] => Array
        (
            [0] => ✝
            [1] => 17
        )
    [1] => Array
        (
            [0] => ✝
            [1] => 32
        )
    [2] => Array
        (
            [0] => ✝
            [1] => 44
        )

Я пробовал использовать (✝), но, конечно, это выберет все экземпляры, включая слова без звездочек. Затем я попробовал \*[^ ]*(✝)[^ ]*\* , но это дает мне только последний экземпляр одним словом. Я пробовал много других вариантов, но все были неправильными.

Чтобы уточнить: звездочка может стоять в любом месте строки, но всегда в начале и в конце слова. Открывающая звездочка всегда предшествует пробелу, за исключением начала строки, а закрывающая звездочка всегда заканчивается пробелом, за исключением конца строки. Надо добавить, что знаки препинания могут находиться внутри этих звездочек . ✝ - это именно (и только) то, что мне нужно для захвата, и может быть в любой позиции в слове.

1 Ответ

0 голосов
/ 14 июля 2020

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

(?:\*|\G(?!^))[^&*]*(?>&(?!#)[^&*]*)*\K✝(?=[^*]*\*)

Объяснение

  • (?: Без захвата группа
    • \* Соответствие *
    • | Или
    • \G(?!^) Подтверждение конца предыдущего совпадения, а не начала
  • ) Закрыть группу без захвата
  • [^&*]* Сопоставить 0+ раз любые символы, кроме & и *
  • (?> Atomi c group
    • &(?!#) Соответствует &, только если за ним непосредственно не следует #
    • [^&*]* Соответствует 0+ раз любой символ, кроме & и *
  • )* Закройте группу atomi c и повторите 0+ раз
  • \K Очистите буфер сопоставления (забудьте, что сопоставлено до сих пор)
  • ✝ Дословное совпадение
  • (?=[^*]*\*) Положительный просмотр вперед, утверждение * справа

Regex demo | Php демо

Например

$re = '/(?:\*|\G(?!^))[^&*]*(?>&(?!#)[^&*]*)*\K✝(?=[^*]*\*)/m';
$str = '✝his is *✝he* *in✝erne✝*';
preg_match_all($re, $str, $matches, PREG_OFFSET_CAPTURE);
print_r($matches[0]);

Выход

Array
(
    [0] => Array
        (
            [0] => ✝
            [1] => 16
        )

    [1] => Array
        (
            [0] => ✝
            [1] => 31
        )

    [2] => Array
        (
            [0] => ✝
            [1] => 43
        )

)

Примечание Смещение на 1 меньше ожидаемого, так как строка начинает отсчет с 0. См. PREG_OFFSET_CAPTURE


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

(?:\*|\G(?!^))[^&*\r\n]*(?>&(?!#)[^&*\\rn]*)*\K&#(?:x271D|169);(?=[^*\r\n]*\*)

Regex demo

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...