正则表达式:如何选择性地捕获一个组

4

我想让子字符串变成可选项。

以下是源代码:

Movie TOTO S09 E22 2022 Copyright

我希望能够选择性地捕获子字符串:S09 E22

到目前为止,我尝试过:

/(Movie)(.*)(S\d\d\s*E\d\d)?/gmi

问题在于它最终匹配到了S09 E22 2022版权而不仅仅是S09 E22:
Match 1 : 0-33  Movie TOTO S09 E22 2022 Copyright 
Group 1 : 0-5   Movie
Group 2:  5-33   TOTO S09 E22 2022 Copyright

有没有办法解决这个问题?
谢谢

欢迎来到SO并感谢您分享您的努力。您正在尝试这个正则表达式的语言是什么? - RavinderSingh13
1
我正在使用默认语言为PCRE(>=PHP 7.3)的regex101。 - Prakein
4个回答

7

你得到了这个匹配是因为.*是贪婪的,会一直匹配直到字符串末尾。

然后你的(S\d\d\s*E\d\d)?是可选的,所以它将保持匹配并且不会回溯。

如果你不想要S09或E22的部分匹配,且4位数字的年份不是必需的,并且你有超过一个单词长度的电影名称,那么可以使用pcre:

\b(Movie)\b\h+((?:(?!\h+[SE]\d+\b).)*)(?:\h(S\d+\h+E\d+))?
  • \b(Movie)\b 捕获单词Movie
  • ( 捕获组
    • (?: 不捕获分组以整体重复
      • (?!\h+[SE]\d+\b). 如果S01或E22部分不直接在右侧,则匹配任何字符(其中[SE]匹配SE字符,\h匹配水平空白字符)
    • )* 关闭不捕获的组并可选地重复它
  • ) 结束捕获组
  • (?:\h(S\d+\h+E\d+)) 可选地捕获S01 E22部分(其中\d+匹配1个或多个数字)

正则表达式演示

另一个选项是捕获S01 E22部分的捕获组,否则匹配其余行。

\b(Movie)\h+([^S\n]*(?:S(?!\d+\h+E\d+\b)[^S\n]*)*+)(S\d+\h+E\d+)?

正则表达式演示


5
通过你展示的示例和尝试,请尝试以下正则表达式。
^Movie\s+\S+\s+(S\d{2}\s+E\d{2}(?=\s+\d{4}))

这里是用于正则表达式的在线演示

说明: 上面使用的正则表达式的详细说明。

^Movie\s+\S+\s+  ##Matching string Movie from starting of value followed by spaces non-spaces and spaces.
(S\d{2}\s+E\d{2} ##Creating one and only capturing group where matching:
                 ##S followed by 2 digits followed by spaces followed by E and 2 digits.
  (?=\s+\d{4})   ##Making sure by positive lookahead that previous regex is followed by spaces and 4 digits.
)                ##Closing capturing group here.

5

3

您的正则表达式存在以下几个问题:

  • 电影 后面的空格不被考虑。
  • (.*) 匹配的是电影之后的所有内容。

可以在https://regex101.com/上测试。

(Movie\s*)(\w*\s*)(S\d{2}\s*E\d{2}\s*)?((?:\w*\s*)*)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接