¿Por qué esta expresión regular da como resultado cuatro elementos?

Quiero dividir una cadena por , -> , => , o envueltos con varios espacios, lo que significa que puedo obtener dos artículos, she y he , de las siguientes cadenas después de dividirse:
"she he", "she he", "she he ", "she he ", "she->he", "she ->he", "she=>he", "she=> he", " she-> he ", " she => he \n"

He intentado usar esto:

 re.compile("(?\\s*)|[\\s+\t])(?!$\n)(?=[^\s])").split(' she -> he \n') 

Lo que obtengo es una lista con cuatro elementos: [' she', ' -> ', ' -> ', 'he \n'] .

Y para esto,

 re.compile("(?\\s*)|[\\s+\t])(?!$\n)(?=[^\s])").split('she he') 

Entiendo esto: ['she', ' ', None, 'he'] .

¿Por qué hay cuatro elementos? ¿Y cómo puedo obtener solo dos sin los dos medios?

Si puedes simplemente despojar tu cadena de entrada. Desde su descripción, todo lo que necesita es dividir las palabras en \s+ o \s*->\s* o \s*=>\s*

Así que aquí está mi solución:

 p = re.compile(r'\s*[-=]>\s*|\s+') input1 = "she he" input2 = " she -> he \n".strip() print p.split(input1) print p.split(input2) 

Tu salida sería solo ‘ella’ y ‘él’:

 ['she', 'he'] 

Como ya se indicó en los comentarios, cada par de paréntesis en su regex forma un grupo de captura, y cada uno de ellos es devuelto por la función regex split() . Según la documentación ,

Si se usan paréntesis de captura en el patrón, entonces el texto de todos los grupos en el patrón también se devuelve como parte de la lista resultante.

Las expresiones regulares de Python tienen una facilidad para los paréntesis que no capturan. Utiliza (?: lugar de solo ( para que el paréntesis de apertura se agrupe sin capturar).

 >>> re.compile("(?\\s*)|[\\s+\t])(?!$\n)(?=[^\s])").split('she he') ['she', ' ', None, 'he'] >>> re.compile("(?\\s*)|[\\s+\t])(?!$\n)(?=[^\s])").split('she he') ['she', 'he'] 

No está exactamente claro por qué incluye una pestaña explícitamente en la clase de caracteres con \s ; la \s ya incluye la pestaña como uno de los muchos caracteres de espacio en blanco que coincide.

Tampoco está claro qué espera $\n para coincidir. $ es el final de la línea y \n es un carácter literal de nueva línea, por lo que parece que estás tratando de lidiar con las nuevas líneas; pero $ solo ya cubre eso. La única diferencia entre $ y $\n es que si el final de la cadena (la última línea de una cadena multilínea) no termina en una nueva línea, eso no coincidirá con la última.

El (? También es peculiar: una mejor manera de evitar la coincidencia de una cadena vacía es asegurarse de que su expresión regular siempre coincida con algo.

De tus requerimientos, parece que

 re.compile(r'\s*[-=]>\s*|\s+').split('he she') 

Haría lo que quiera de manera más sucinta y legible. Esto hace coincidir una flecha ASCII (simple o doble) con espacios en blanco opcionales en ambos lados, o si esto falla, vuelve a una secuencia de espacios en blanco.

Cada vez que usa paréntesis “()” está creando un grupo de captura. Un grupo de captura es una parte de un partido. Una coincidencia siempre se refiere a la cadena completa de expresiones regulares. Es por eso que estás obteniendo 4 resultados.

La documentación dice: “Si los paréntesis de captura se utilizan en el patrón, entonces el texto de todos los grupos en el patrón también se devuelve como parte de la lista resultante”.

Puede intentar hacer que los grupos “no capturen” como sugirió Rawing. Haga esto simplemente al insertar “?:” Dentro de los paréntesis que no desea que se capturen.

Simplemente dejaría de lado los paréntesis:

 res = re.compile("\\s*[-=]>\\s*|\\s*").split(' she -> he \n') res = filter(None, res) res = list(res) 

Salida:

 ['she', 'he']