Как сделать preg_replace, который соответствует только определенным условиям? - PullRequest
3 голосов
/ 25 июня 2019

Я изо всех сил пытаюсь написать команду preg_replace, которая достигает того, что мне нужно.

По сути, у меня есть следующий массив (все элементы следуют одному из этих четырех шаблонов):

$array = array('Dogs/Cats', 'Dogs/Cats/Mice', 'ANIMALS/SPECIES Dogs/Cats/Mice', '(Animals/Species) Dogs/Cats/Mice' );

Мне нужно получить следующий результат:

Dogs/Cats = Dogs or Cats

Dogs/Cats/Mice = Dogs or Cats or Mice

ANIMALS/SPECIES Dogs/Cats/Mice = ANIMALS/SPECIES Dogs or Cats or Mice

(Animals/Species) Dogs/Cats/Mice = (Animals/Species) Dogs or Cats or Mice

Так что в основном заменяйте косые черты во всех, которые не являются заглавными буквами или скобками.

Я начинаю понимать, но все еще нуждаюсь в руководстве:

preg_replace('/(\(.*\)|[A-Z]\W[A-Z])[\W\s\/]/', '$1 or', $array);

Как вы можете видеть, это распознает первые паттерны, но я не знаю, куда идти

Спасибо!

Ответы [ 2 ]

2 голосов
/ 25 июня 2019

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

Вы можете дополнительно соответствовать ANIMALS/SPECIESили (Animals/Species) в начале.

(?:^(?:\(\w+/\w+\)\h+|[A-Z]+/[A-Z]+\h+)?|\G(?!^))\w+\K/

Пояснение

  • (?: Группа без захвата
    • ^ Начать утверждениестроки
    • (?: Группа без захвата, сопоставьте либо
      • \(\w+/\w+\)\h+ Соответствие между (....) 1+ символами слова с / между окончанием 1+ горизонтальными символами пробела
      • | Или
      • [A-Z]+/[A-Z]+\h+ Матч 1+ раз [AZ], / и снова 1+ раз [A-Z]
    • )? Закрыть группу без захвата и сделать ее необязательной
    • | Или
    • \G(?!^) Подтвердить позицию в предыдущем матче
  • )\w+ Закрытьгруппа без захвата и соответствует 1+ раз слово char
  • \K/ Забудьте, что было найдено, и сопоставьте /

Regex demo | Php demo

При замене используйте пробел or и пробел

Например

$array = array('Dogs/Cats', 'Dogs/Cats/Mice', 'ANIMALS/SPECIES Dogs/Cats/Mice', '(Animals/Species) Dogs/Cats/Mice');
$re = '~(?:^(?:\(\w+/\w+\)\h+|[A-Z]+/[A-Z]+\h+)?|\G(?!^))\w+\K/~';
$array = preg_replace($re, " or ", $array);
print_r($array);

Результат:

Array
(
    [0] => Dogs or Cats
    [1] => Dogs or Cats or Mice
    [2] => ANIMALS/SPECIES Dogs or Cats or Mice
    [3] => (Animals/Species) Dogs or Cats or Mice
)
1 голос
/ 26 июня 2019

То, как вы представляете свою проблему с примерами строк, делает:

$result = preg_replace('~(?:\S+ )?[^/]*+\K.~', ' or ', $array);

выглядит достаточно.Другими словами, вам нужно только проверить, есть ли место где-то, чтобы использовать начало строки до тех пор, пока она не будет удалена из результата совпадения, используя \K.

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

Что если категория, подкатегория или элемент содержат пробел?

~
(?:^
    (?:
        \( [^)]* \)
      |
        \p{Lu}+ (?> [ ] \p{Lu}+ \b )* 
        (?> / \p{Lu}+ (?> [ ] \p{Lu}+ \b )* )* 
    ) 
    [ ]
)?

[^/]*+ \K .
~xu

demo

Таким же образом, чтобы иметь дело с дефисами, одинарными кавычками или чем-то еще, вы можете заменить [ ] на [^\pL/] (класс, исключающий буквы и косую черту) или что-то ещеболее конкретно.

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