Python y sed son codiciosos por defecto, pero ... Python regex intenta evaluar de izquierda a derecha en todas las circunstancias, a pesar de que debe hacer una traza inversa al estado anterior si la rama que se intenta no puede continuar haciendo coincidir Sed regex, por el contrario, se optimizan antes de la evaluación con el fin de evitar una traza inversa innecesaria, mediante la reescritura de la expresión regular a una forma más determinista. Por lo tanto, el patrón opcional combinado "aab" probablemente se pruebe antes que la "a" simple porque se intenta primero la cadena más específica posible.
patrón Python coincide con el "aabb" cadena dos veces como "aab" "b" + (marcada entre "< >")
>>> re.sub("a*((ab)*)b", r"<\1>", "aabb")
'<><>'
mientras sed partidos todo el "aabb" por una sustitución:
$ echo "aabb" | sed "s/a*\(\(ab\)*\)b/<\1>/"
<ab>
El algoritmo de retroceso de Pyge regex se explica bien en regex howto - Repeating Things en dos párrafos introducidos por las palabras "Un ejemplo paso a paso ...". Hace IMO exactamente lo que se describe regex docs: "A medida que se explora la cadena objetivo, las RE se separan por '|' se intentan de izquierda a derecha. "
Demostración
El orden de "(| a | bis)" por cierto. "(AA | a |)" es respetado por Python
>>> re.sub("(?:|a|aa)((ab)*)b", r"<\1>", "aabb")
'<ab>'
>>> re.sub("(?:aa|a|)((ab)*)b", r"<\1>", "aabb")
'<><>'
pero esta orden es ignorado por sed dado que sed optimiza expresiones regulares. La coincidencia de "aab" + "b" se puede reproducir eliminando la opción "a" del patrón.
$ echo "aabb" | sed "s/\(\|a\|aa\)\(\(ab\)*\)b/<\2>/g"
<ab>
$ echo "aabb" | sed "s/\(aa\|a\|\)\(\(ab\)*\)b/<\2>/g"
<ab>
$ echo "aabb" | sed "s/\(aa\|\)\(\(ab\)*\)b/<\2>/g"
<><>
Editar: Me eliminado todo sobre DFA/NFA porque no puedo demostrarlo a partir de textos actuales.
alguna parte leí que "SED/awk utiliza un AFD" y "Python/Perl/Java utilizan un NFA". Cambia la semántica con alternancias (retroceso?) ... ¿podría estar relacionado? –
@pst: Tal vez te estoy malinterpretando, pero parece que cualquier enfoque basado en retroceso usaría un DFA; el efecto de usar un NFA sería eliminar la necesidad de retroceder, ya que todas las ramas se examinan simultáneamente. Entonces, esperaría que Perl/Python/Java/etc. para usar un DFA. ¿Es posible que leas lo contrario de lo que escribiste: tal vez lees que sed/awk usa un NFA y Perl/Python/Java, etc. usa un DFA? – ruakh
@pst: Y * explicaría * el comportamiento observado, si sed/awk utiliza un NFA, y luego elija la forma de coincidencia que proporcionó la coincidencia más larga. En este caso, permitir '\ (\ (ab \) * \)' hacer coincidir 'ab' produce una coincidencia global más larga,' aabb', y hacer coincidir la cadena vacía, ya que esto último significaría que la expresión regular como un todo solo coincidiría con 'aab'. – ruakh