Scala regexps: как к ответным матчам как массив или список

Существует ли простой способ возвратить соответствия 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

Вызов "длины" так или иначе изменяет состояние итератора. Что продолжается здесь?

14
задан Nathaniel Ford 7 December 2016 в 19:00
поделиться

3 ответа

Хорошо, во-первых, поймите, что 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.

27
ответ дан 1 December 2019 в 07:12
поделиться

Существует разница между тем, как 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))
9
ответ дан 1 December 2019 в 07:12
поделиться
121 --- 2675135-

Попробуйте:

  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)
  }
2
ответ дан 1 December 2019 в 07:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: