有一种简单的方法可以将正则表达式匹配作为数组返回吗?
以下是我在2.7.7
尝试的方式:
val s = """6 1 2"""
val re = """(\d+)\s(\d+)\s(\d+)""".r
for (m <- re.findAllIn (s)) println (m) // prints "6 1 2"
re.findAllIn (s).toList.length // 3? No! It returns 1!
但我接着尝试了:
s match {
case re (m1, m2, m3) => println (m1)
}
这很好用! m1是6,m2是1,等等。
然后我发现了一些让我感到困惑的事情:
val mit = re.findAllIn (s)
println (mit.toString)
println (mit.length)
println (mit.toString)
打印:
non-empty iterator
1
empty iterator
“length”调用以某种方式修改迭代器的状态。这是怎么回事?
答案 0 :(得分:27)
好的,首先,要了解findAllIn
会返回Iterator
。 Iterator
是一次消费可变对象。你做的任何事都会改变它。如果您不熟悉迭代器,请阅读它们。如果您希望它可重用,则将findAllIn的结果转换为List
,并仅使用该列表。
现在,您似乎想要所有匹配的群组,而不是所有匹配。方法findAllIn
将返回可在字符串中找到的完整正则表达式的所有匹配项。例如:
scala> val s = """6 1 2, 4 1 3"""
s: java.lang.String = 6 1 2, 4 1 3
scala> val re = """(\d+)\s(\d+)\s(\d+)""".r
re: scala.util.matching.Regex = (\d+)\s(\d+)\s(\d+)
scala> for(m <- re.findAllIn(s)) println(m)
6 1 2
4 1 3
看到有两个匹配,并且它们都不包含字符串中间的“,”,因为那不是任何匹配的一部分。
如果你想要这些小组,你可以这样得到它们:
scala> val s = """6 1 2"""
s: java.lang.String = 6 1 2
scala> re.findFirstMatchIn(s)
res4: Option[scala.util.matching.Regex.Match] = Some(6 1 2)
scala> res4.get.subgroups
res5: List[String] = List(6, 1, 2)
或者,使用findAllIn
,如下所示:
scala> val s = """6 1 2"""
s: java.lang.String = 6 1 2
scala> for(m <- re.findAllIn(s).matchData; e <- m.subgroups) println(e)
6
1
2
matchData
方法将Iterator
返回Match
而不是String
。
答案 1 :(得分:9)
unapplySeq如何解释多个组与findAllIn的工作方式之间存在差异。 findAllIn在字符串上扫描你的模式并返回匹配的每个字符串(如果成功则前进到匹配,或者如果失败则返回一个字符)。
所以,例如:
scala> val s = "gecko 6 1 2 3 4 5"
scala> re.findAllIn(s).toList
res3: List[String] = List(6 1 2, 3 4 5)
另一方面,unapplySeq假设完美与序列匹配。
scala> re.unapplySeq(s)
res4: Option[List[String]] = None
因此,如果要解析在精确正则表达式字符串中指定的组,请使用unapplySeq。如果要查找看起来像正则表达式模式的字符串子集,请使用findAllIn。如果你想两者兼顾,请自行链接:
scala> re.findAllIn(s).flatMap(text => re.unapplySeq(text).elements )
res5: List[List[String]] = List(List(6, 1, 2), List(3, 4, 5))
答案 2 :(得分:2)
试试这个:
val s = """6 1 2"""
val re = """\d+""".r
println(re.findAllIn(s).toList) // List(6, 1, 2)
println(re.findAllIn(s).toList.length) // 3
并且,如果你真的需要一个单一的Regex中的匹配组列表:
val s = """6 1 2"""
val Re = """(\d+)\s(\d+)\s(\d+)""".r
s match { // this is just sugar for calling Re.unapplySeq(s)
case Re(mg@_*) => println(mg) // List(6, 1, 2)
}