Существует ли простой способ возвратить соответствия regex как массив?
Вот то, как я пробую в 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
Вызов "длины" так или иначе изменяет состояние итератора. Что продолжается здесь?
Хорошо, во-первых, поймите, что findAllIn
возвращает Iterator
. Итератор Итератор
- это переменный объект потребления. Любое, что вы с ним сделаете, изменит его. Читайте на итераторах, если вы не знакомы с ними. Если вы хотите, чтобы он был многократно использован, то конвертируйте результат findAllIn в List
, и используйте только этот список.
Похоже, вы хотите, чтобы все совпадения группы , а не все. Метод findAllIn
вернет все совпадения регекса full, которые могут быть найдены на строке. Например:
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
See, что есть два совпадения, и ни одно из них не включает ", " в середине строки, так как это не часть любого совпадения.
Если вам нужны группы, вы можете получить их так:
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
.
Существует разница между тем, как unapplyseq интерпретирует Mulitple Groups и как делает 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
Итак, если вы хотите разбирать группы, которые вы указали в точной строке Regex, используйте unapplyseq. Если вы хотите найти эти подмножества строки, которые выглядят как ваш рисунок Regex, используйте Findallin. Если вы хотите сделать оба, цепь их самостоятельно:
scala> re.findAllIn(s).flatMap(text => re.unapplySeq(text).elements )
res5: List[List[String]] = List(List(6, 1, 2), List(3, 4, 5))
Попробуйте:
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)
}