Necesito capturar varios grupos del mismo patrón. Supongamos que tengo la siguiente cadena:
HELLO,THERE,WORLD
Y he escrito un siguiente patrón
^(?:([A-Z]+),?)+$
Lo que quiero que haga es capturar cada palabra, de modo que el Grupo 1 sea: "HOLA", el Grupo 2 sea "ALLÍ" y el Grupo 3 sea "MUNDO" Lo que mi expresión regular está capturando solo la última, que es " MUNDO".
Estoy probando mi expresión regular aquí y quiero usarla con Swift (¿tal vez hay una forma en Swift de obtener resultados intermedios de alguna manera, para poder usarlos?)
ACTUALIZACIÓN: No quiero usar split
. Ahora solo necesito saber cómo capturar todos los grupos que han coincidido con el patrón, no solo el último.
,
?[A-Z]+
o[^,]+
capturar los resultados?Respuestas:
Con un grupo en el patrón, solo puede obtener un resultado exacto en ese grupo. Si su grupo de captura se repite por el patrón (usó el
+
cuantificador en el grupo de no captura circundante), solo se almacena el último valor que coincide con él.Debe usar las funciones de implementación de expresiones regulares de su lenguaje para encontrar todas las coincidencias de un patrón, luego tendría que eliminar los anclajes y el cuantificador del grupo que no captura (y también podría omitir el grupo que no captura).
Alternativamente, expanda su expresión regular y deje que el patrón contenga un grupo de captura por grupo que desea obtener en el resultado:
^([A-Z]+),([A-Z]+),([A-Z]+)$
fuente
Creo que necesitas algo como esto ...
b="HELLO,THERE,WORLD" re.findall('[\w]+',b)
Que en Python3 volverá
['HELLO', 'THERE', 'WORLD']
fuente
re.findall('\w+',b)
es 2 caracteres más corto. No es necesaria una clase de personaje, ya que solo tiene una expresiónSolo para proporcionar un ejemplo adicional del párrafo 2 en la respuesta. No estoy seguro de cuán crítico es para ti tener tres grupos en un partido en lugar de tres partidos usando un grupo. Por ejemplo, en groovy:
def subject = "HELLO,THERE,WORLD" def pat = "([A-Z]+)" def m = (subject =~ pat) m.eachWithIndex{ g,i -> println "Match #$i: ${g[1]}" } Match #0: HELLO Match #1: THERE Match #2: WORLD
fuente
Después de leer la respuesta de Byte Commander , quiero presentar una pequeña mejora posible:
Puede generar una
n
expresión regular que coincidirá con cualquiera de las palabras, siempre quen
esté predeterminada. Por ejemplo, si quiero hacer coincidir entre 1 y 3 palabras, la expresión regular:^([A-Z]+)(?:,([A-Z]+))?(?:,([A-Z]+))?$
coincidirá con las siguientes oraciones, con uno, dos o tres grupos de captura.
HELLO,LITTLE,WORLD HELLO,WORLD HELLO
Puede ver una explicación completamente detallada sobre esta expresión regular en Regex101 .
Como dije, es bastante fácil generar esta expresión regular para cualquier grupo que desee utilizando su idioma favorito. Como no soy muy rápido, aquí hay un ejemplo de rubí:
def make_regexp(group_regexp, count: 3, delimiter: ",") regexp_str = "^(#{group_regexp})" (count - 1).times.each do regexp_str += "(?:#{delimiter}(#{group_regexp}))?" end regexp_str += "$" return regexp_str end puts make_regexp("[A-Z]+")
Dicho esto, sugeriría no usar expresiones regulares en ese caso, hay muchas otras herramientas excelentes, desde
split
patrones simples hasta algunos patrones de tokenización, según sus necesidades. En mi humilde opinión, una expresión regular no es uno de ellos. Por ejemplo, en ruby usaría algo comostr.split(",")
ostr.scan(/[A-Z]+/)
fuente
La distinción clave es repetir un grupo capturado en lugar de capturar un grupo repetido .
Como ya ha descubierto, la diferencia es que la repetición de un grupo capturado captura solo la última iteración. La captura de un grupo repetido captura todas las iteraciones.
En PCRE (PHP):
Match 1, Group 1. 0-5 HELLO Match 2, Group 1. 6-11 THERE Match 3, Group 1. 12-20 BRUTALLY Match 4, Group 1. 21-26 CRUEL Match 5, Group 1. 27-32 WORLD
Dado que todas las capturas están en el Grupo 1, solo es necesario
$1
realizar una sustitución.Usé la siguiente forma general de esta expresión regular:
Ejemplo en regex101
fuente
De hecho, tiene un grupo de captura que coincidirá varias veces. No múltiples grupos de captura.
solución javascript (js):
let string = "HI,THERE,TOM"; let myRegexp = /([A-Z]+),?/g; //modify as you like let match = myRegexp.exec(string); //js function, output described below while(match!=null){ //loops through matches console.log(match[1]); //do whatever you want with each match match = myRegexp.exec(bob); //find next match }
Salida:
HI THERE TOM
Sintaxis:
// matched text: match[0] // match start: match.index // capturing group n: match[n]
Como puede ver, esto funcionará para cualquier número de coincidencias.
fuente
Sé que mi respuesta llegó tarde pero hoy me pasa y lo resolví con el siguiente enfoque:
^(([A-Z]+),)+([A-Z]+)$
Entonces, el primer grupo
(([A-Z]+),)+
coincidirá con todos los patrones repetidos excepto el último([A-Z]+)
que coincidirá con el final. y esto será dinámico sin importar cuántos grupos repetidos en la cadena.fuente
Lo siento, no Swift, solo una prueba de concepto en el idioma más cercano.
// JavaScript POC. Output: // Matches: ["GOODBYE","CRUEL","WORLD","IM","LEAVING","U","TODAY"] let str = `GOODBYE,CRUEL,WORLD,IM,LEAVING,U,TODAY` let matches = []; function recurse(str, matches) { let regex = /^((,?([A-Z]+))+)$/gm let m while ((m = regex.exec(str)) !== null) { matches.unshift(m[3]) return str.replace(m[2], '') } return "bzzt!" } while ((str = recurse(str, matches)) != "bzzt!") ; console.log("Matches: ", JSON.stringify(matches))
Nota: Si realmente fuera a usar esto, usaría la posición de la coincidencia dada por la función de coincidencia de expresiones regulares, no un reemplazo de cadena.
fuente