双正则表达式匹配
Double regex matches
我 preg_match_all 使用不同的模式遍历字符串。有时这些模式看起来很像,但略有不同。
现在我正在寻找一种方法来阻止模式 A 匹配只有模式 B - 在 4 位数字前面有一个 'T' - 应该匹配的字符串。
我 运行 遇到的问题是模式 A 也匹配模式 B:
甲:
(\d{4})(A|B)?(C|D)?
...匹配 1234、1234A、1234AD 等
乙:
我还有一个模式:
T(\d{4})\/(\d{4})
... 匹配如下字符串:T7878/6767
结果
当 运行 a preg_match_all on "T7878/6767 1234AD",A 将给出以下匹配:
7878, 6767, 1234AD
有没有人建议如何防止 A 在字符串中匹配 B,例如 "Some text T7878/6767 1234AD and some more text"?
非常感谢您的帮助!
根据您的要求,您当前的正则表达式并没有真正起作用。 (A|B)?(C|D)?
永远不会匹配 AB
。所以我认为你的意思是 [ABCD]
这是您的新正则表达式:
T(\d{4})\/(\d{4}) (\d{4}[ABCD]*)
对于字符串输入:
T7878/6767 1234AB
我们得到组:
Match 1
Full match 0-17 `T7878/6767 1234AB`
Group 1. 1-5 `7878`
Group 2. 6-10 `6767`
Group 3. 11-17 `1234AB`
有边界的场景
如果您只想匹配某些边界内的那些特定字符串,请在模式的每一侧使用这些边界模式。
如果您希望在每次匹配之前有一个空白边界,则在模式的开头添加 (?<!\S)
负向回顾。如果您希望在匹配结束时出现空白边界,请添加 (?!\S)
负先行。如果可以有任何字符(就像你原来的问题一样),那么 SKIP-FAIL 是唯一的方法(见下文)。
因此,在第一种情况下,您可以使用
(?<!\S)(\d{4})([AB]?)([CD]?)(?!\S)
和
(?<!\S)T(\d{4})\/(\d{4})(?!\S)
参见 Pattern 1 demo and Pattern 2 demo。
没有特定边界的场景
您需要确保在使用第一个模式解析字符串时跳过第二个模式。为此使用 SKIP-FAIL technique:
'~T\d{4}/\d{4}(*SKIP)(*F)|(\d{4})(A|B)?(C|D)?~'
参见regex demo。
如果不需要捕获组,可以简化为
'~T\d{4}/\d{4}(*SKIP)(*F)|\d{4}[AB]?[CD]?~'
详情
T\d{4}/\d{4}
- T
后跟 4 位数字,/
和另外 4 位数字
(*SKIP)(*F)
- 匹配的文本被丢弃,从匹配的文本末尾开始搜索下一个匹配项
|
- 或
\d{4}[AB]?[CD]?
- 4 位数字,然后可选 A
或 B
,然后可选 C
或 D
.
您的语法非常具体,因此您只需要使用正则表达式即可。摆脱你所有的捕获组,因为他们把事情搞砸了。您只需要两个与您的字符串语法完全匹配的组。
第一组查找单词边界,然后是 T,然后是 4 位数字,然后是/然后是 4 位数字和一个分词符。
第二组匹配 4 位数字,然后匹配字母 A-D 0 到 2 次。它有一个负向后视,所以只有在 4 位数字之前有一个空白字符时才会匹配
(\bT\d{4}\/\d{4}\b)|(?<!\S)(\d{4}[A-D]{0,2})
预匹配所有输出:
Array
(
[0] => Array
(
[0] => T7878/6767
[1] => 1234AB
)
[1] => Array
(
[0] => T7878/6767
[1] =>
)
[2] => Array
(
[0] =>
[1] => 1234AB
)
)
我 preg_match_all 使用不同的模式遍历字符串。有时这些模式看起来很像,但略有不同。
现在我正在寻找一种方法来阻止模式 A 匹配只有模式 B - 在 4 位数字前面有一个 'T' - 应该匹配的字符串。
我 运行 遇到的问题是模式 A 也匹配模式 B:
甲:
(\d{4})(A|B)?(C|D)?
...匹配 1234、1234A、1234AD 等
乙:
我还有一个模式:
T(\d{4})\/(\d{4})
... 匹配如下字符串:T7878/6767
结果
当 运行 a preg_match_all on "T7878/6767 1234AD",A 将给出以下匹配:
7878, 6767, 1234AD
有没有人建议如何防止 A 在字符串中匹配 B,例如 "Some text T7878/6767 1234AD and some more text"?
非常感谢您的帮助!
根据您的要求,您当前的正则表达式并没有真正起作用。 (A|B)?(C|D)?
永远不会匹配 AB
。所以我认为你的意思是 [ABCD]
这是您的新正则表达式:
T(\d{4})\/(\d{4}) (\d{4}[ABCD]*)
对于字符串输入:
T7878/6767 1234AB
我们得到组:
Match 1
Full match 0-17 `T7878/6767 1234AB`
Group 1. 1-5 `7878`
Group 2. 6-10 `6767`
Group 3. 11-17 `1234AB`
有边界的场景
如果您只想匹配某些边界内的那些特定字符串,请在模式的每一侧使用这些边界模式。
如果您希望在每次匹配之前有一个空白边界,则在模式的开头添加 (?<!\S)
负向回顾。如果您希望在匹配结束时出现空白边界,请添加 (?!\S)
负先行。如果可以有任何字符(就像你原来的问题一样),那么 SKIP-FAIL 是唯一的方法(见下文)。
因此,在第一种情况下,您可以使用
(?<!\S)(\d{4})([AB]?)([CD]?)(?!\S)
和
(?<!\S)T(\d{4})\/(\d{4})(?!\S)
参见 Pattern 1 demo and Pattern 2 demo。
没有特定边界的场景
您需要确保在使用第一个模式解析字符串时跳过第二个模式。为此使用 SKIP-FAIL technique:
'~T\d{4}/\d{4}(*SKIP)(*F)|(\d{4})(A|B)?(C|D)?~'
参见regex demo。
如果不需要捕获组,可以简化为
'~T\d{4}/\d{4}(*SKIP)(*F)|\d{4}[AB]?[CD]?~'
详情
T\d{4}/\d{4}
-T
后跟 4 位数字,/
和另外 4 位数字(*SKIP)(*F)
- 匹配的文本被丢弃,从匹配的文本末尾开始搜索下一个匹配项|
- 或\d{4}[AB]?[CD]?
- 4 位数字,然后可选A
或B
,然后可选C
或D
.
您的语法非常具体,因此您只需要使用正则表达式即可。摆脱你所有的捕获组,因为他们把事情搞砸了。您只需要两个与您的字符串语法完全匹配的组。
第一组查找单词边界,然后是 T,然后是 4 位数字,然后是/然后是 4 位数字和一个分词符。
第二组匹配 4 位数字,然后匹配字母 A-D 0 到 2 次。它有一个负向后视,所以只有在 4 位数字之前有一个空白字符时才会匹配
(\bT\d{4}\/\d{4}\b)|(?<!\S)(\d{4}[A-D]{0,2})
预匹配所有输出:
Array
(
[0] => Array
(
[0] => T7878/6767
[1] => 1234AB
)
[1] => Array
(
[0] => T7878/6767
[1] =>
)
[2] => Array
(
[0] =>
[1] => 1234AB
)
)