如何只匹配特定条件的preg_replace?

时间:2019-06-25 12:55:31

标签: php regex

我正在努力编写满足我需要的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 个答案:

答案 0 :(得分:2)

您可以使用\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次以上[A-Z],/,再匹配1次以上[A-Z]
    • )?关闭非捕获组并将其设置为可选
    • |
    • \G(?!^)在上一场比赛中保持位置
  • )\w+关闭非捕获组并匹配一个字符char 1次以上
  • \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 :(得分:1)

使用示例字符串来表达问题的方式是:

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

看起来足够了。换句话说,您只需要检查是否有空间可以占用字符串的开头直到它开始,并使用\K从匹配结果中将其丢弃。

但是为了避免将来失望,有时让自己陷入魔鬼的怀抱中考虑更复杂的情况并提出令人尴尬的问题有时会很有用:

如果类别,子类别或项目包含空格怎么办?

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

[^/]*+ \K .
~xu

demo

以相同的方式,要处理连字符,单引号或其他内容,可以将[ ]替换为[^\pL/](不包括字母和斜杠的类)或更具体些。