2010-01-14 14 views
11

¿Hay una manera simple de devolver las coincidencias de expresiones regulares como una matriz?
Así es como estoy tratando de 2.7.7:Scala regexps: cómo devolver coincidencias como una matriz o una lista

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! 

Pero entonces me trataron:

s match { 
    case re (m1, m2, m3) => println (m1) 
} 

y esto funciona bien! m1 es 6, m2 es 1, etc.

Entonces me encontré con algo que añade a mi confusión:

val mit = re.findAllIn (s) 
println (mit.toString) 
println (mit.length) 
println (mit.toString) 

que imprime:

non-empty iterator 
1 
empty iterator 

La llamada "longitud" de alguna manera modifica el estado del iterador. ¿Que esta pasando aqui?

+0

Tu llamada a findAllIn (s) está haciendo coincidir toda la cadena, por lo que la lista resultante no es List (6 1 2), pero realmente es List ("6 1 2") de longitud 1 –

Respuesta

24

Ok, en primer lugar, entender que devuelve un findAllInIterator. Un Iterator es un objeto mutable de consumo único. CUALQUIER COSA que le hagas lo cambiará. Lea sobre iteradores si no está familiarizado con ellos. Si desea que sea reutilizable, convierta el resultado de findAllIn en List, y solo use esa lista.

Ahora, parece que quiere todos los grupos correspondientes , no todas las coincidencias. El método findAllIn devolverá todas las coincidencias de la completa regex que se pueden encontrar en la cadena. Por ejemplo:

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 

ver que hay dos partidos, y ninguno de ellos incluyen la "" a la mitad de la cadena, ya que no es parte de ningún partido.

Si desea que los grupos, se puede conseguir de esta manera:

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) 

O, usando findAllIn, así:

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 

El método matchData hará una Iterator que devuelve Match vez de String.

+0

No entiendo por qué 'findAllIn' devuelve un' MatchIterator', en lugar de solo 'Iterator [Match]'. Es confuso ya que algunos de los métodos en el nivel de recolección no funcionan. P.ej. si intenta llamar a 'subgroups' como' re.findAllIn (s) .subgroups', fallará, a pesar de que 're.findAllIn (s) .groupCount' sea distinto de cero (2.11.x) – Luciano

+0

@Luciano La diferencia entre' MatchIterator' y 'Iterator [Match]' es que el primero también es 'MatchData'. Sin embargo, el scaladoc advierte: Todos los métodos heredados de 'scala.util.matching.Regex.MatchData' lanzarán una' java.lang.IllegalStateException' hasta que se inicialice el emparejador. El emparejador se puede inicializar invocando 'hasNext' o' next() 'o haciendo que se invoquen estos métodos, como al invocar' toString' o iterar a través de los elementos del iterador. –

2

Prueba esto:

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 

Y, si realmente necesita una lista de los grupos de los partidos dentro de una expresión regular de la chamusquina:

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([email protected]_*) => println(mg) // List(6, 1, 2) 
    } 
9

Hay una diferencia entre la forma en unapplySeq interpreta grupos haya numerosas y cómo findAllIn does. findAllIn escanea tu patrón sobre la cadena y devuelve cada cadena que coincide (avanzando por la coincidencia si tiene éxito, o un personaje si falla).

Así, por ejemplo:

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) 

Por otro lado, unapplySeq asume un partido perfecto a la secuencia.

scala> re.unapplySeq(s) 
res4: Option[List[String]] = None 

lo tanto, si desea analizar Separación de grupos que se han especificado en una cadena de expresiones regulares exacta, utilice unapplySeq. Si desea encontrar los subconjuntos de la cadena que se parecen a su patrón de expresiones regulares, use findAllIn. Si desea hacer ambas cosas, encadenarlos a sí mismo:

scala> re.findAllIn(s).flatMap(text => re.unapplySeq(text).elements) 
res5: List[List[String]] = List(List(6, 1, 2), List(3, 4, 5)) 
Cuestiones relacionadas