我的正则表达式是类似**(A)(([+-]\d{1,2}[YMD])*)**
的东西,它与预期的匹配,例如A + 3M,A-3Y + 5M + 3D等。
但是我想捕获此子模式的所有组**([+-]\d{1,2}[YMD])***
对于以下示例A-3M + 2D,我只能看到4个组。 A-3M+2D (group 0), A(group 1), -3M+2D (group 2), +2D (group 3)
有没有一种方法可以将**-3M**
作为一个单独的组?
通常重复捕获组capture only the last iteration。 Kotlin和Java均是如此,因为这些语言没有任何方法可以跟踪每个捕获组堆栈。
您可以采取的解决方法是,首先对整个字符串与字符串应匹配的特定模式进行验证,然后将字符串提取或分割成多个部分。
对于当前方案,您可以使用
val text = "A-3M+2D"
if (text.matches("""A(?:[+-]\d{1,2}[YMD])*""".toRegex())) {
val results = text.split("(?=[-+])".toRegex())
println(results)
}
// => [A, -3M, +2D]
请参见Kotlin demo
这里,
text.matches("""A(?:[+-]\d{1,2}[YMD])*""".toRegex())
确保整个字符串与A
匹配,然后出现0个或多个+
或-
,1或2位数字,后跟Y
,M
或D
.split("(?=[-+])".toRegex())
在-
或+
之前,用空字符串分割文本。图案详细信息
^
-隐含在.matches()
中-字符串开头A
-一个A
子字符串(?:
-non-capturing group的开头:[+-]
-匹配character class或+
的-
\d{1,2}
-一位到两位数字[YMD]
-与Y
或M
或D
匹配的字符类>)*
-非捕获组的结尾,重复0次或多次(由于[C0]量词)]*
-隐含在\z
中-字符串结尾。[分割时,我们只需要查找matches()
或-
之前的位置,因此我们使用正数+
,lookahead,它与紧随其后的位置(?=[-+])
或+
相匹配。这是一种非消耗模式,匹配的-
或+
不会添加到匹配值中。
具有单个正则表达式的另一种方法
您还可以使用基于-
的正则表达式在字符串的开头首先检查字符串格式,并且只有在成功的情况下才开始匹配连续的子字符串:
\G
请参见
val regex = """(?:\G(?!^)[+-]|^(?=A(?:[+-]\d{1,2}[YMD])*$))[^-+]+""".toRegex() println(regex.findAll("A-3M+2D").map{it.value}.toList()) // => [A, -3M, +2D]
和another Kotlin demo。
详细信息
(?:\G(?!^)[+-]|^(?=A(?:[+-]\d{1,2}[YMD])*$))
或+
(请参阅-
)或(\G(?!^)[+-]
),其后是|
,然后是0或更大出现A
/ +
,1或2位数字,然后出现-
,Y
或M
直到字符串的末尾(请参阅D
)^(?=A(?:[+-]\d{1,2}[YMD])*$)
-除[^-+]+
和-
之外的1个或多个字符。我们不必在这里过分小心,因为前行在字符串开始时就完成了繁重的工作。