Cómo entender gsub (/^.*\//, ”) o la expresión regular

Rompiendo el código de abajo para entender mi comprensión de gsub regulares y gsub :

 str = "abc/def/ghi.rb" str = str.gsub(/^.*\//, '') #str = ghi.rb 

^ : principio de la cadena

\/ : carácter de escape para /

^.*\/ : todo desde el principio hasta la última aparición de / en la cadena

¿Es correcto mi entendimiento de la expresión?

¿Cómo funciona exactamente .* ?

Su comprensión general es correcta. Toda la expresión regular coincidirá con abc/def/ y String#gsub lo reemplazará con una cadena vacía.

Sin embargo, tenga en cuenta que String#gsub no cambia la cadena en su lugar. Esto significa que str contendrá el valor original ( "abc/def/ghi.rb" ) después de la sustitución. Para cambiarlo en su lugar, puedes usar String#gsub! .


En cuanto a cómo funciona .* , El algoritmo que utiliza el motor de expresiones regulares se llama retroceso . Como .* Es codicioso (intentará hacer coincidir tantos personajes como sea posible), puedes pensar que algo así sucederá:

Paso 1 :. .* abc/def/ghi.rb toda la cadena abc/def/ghi.rb Después \/ intenta hacer coincidir una barra diagonal, pero falla (no queda nada para que coincida). .* tiene que retroceder.
Paso 2 :. .* abc/def/ghi.r toda la cadena excepto el último carácter: abc/def/ghi.r Luego \/ intenta hacer coincidir una barra diagonal, pero falla ( / != b ). .* tiene que retroceder.
Paso 3 :. .* Coincide con la cadena completa, excepto los dos últimos caracteres: abc/def/ghi. . Luego \/ intenta hacer coincidir una barra diagonal, pero falla ( / != r ). .* tiene que retroceder.

Paso n :. .* abc/def con abc/def . Después \/ intenta hacer coincidir una barra diagonal y tiene éxito. El emparejamiento termina aquí.

No, no del todo.

  • ^ : principio de una línea
  • \/ : barra escapada (el carácter de escape es \ solo)
  • ^.*\/ : todo desde el principio de una línea hasta la última aparición de / en la cadena

.* depende del modo de la expresión regular. En el modo de línea única (es decir, sin la opción m ), significa la secuencia más larga posible de cero o más caracteres que no son de nueva línea. En el modo multilínea (es decir, con la opción m ), significa la secuencia más larga posible de cero o más caracteres.

Su comprensión es correcta, pero también debe tener en cuenta que la última afirmación es verdadera porque:

 Repetition is greedy by default: as many occurrences as possible are matched while still allowing the overall match to succeed. 

Citado en la documentación de Regexp .

Sí. En resumen, coincide con cualquier número de cualquier carácter ( .* ) Que termina con un literal / ( \/ ).

gsub reemplaza la coincidencia con el segundo argumento (cadena vacía '' ).

No hay ningún problema con su expresión regular, pero File.basename (str) podría ser más apropiado.

Para explicar lo que dijo @Stefen: Realmente parece que estás tratando con una ruta de archivo, y eso hace que tu pregunta sea un problema de XY en el que preguntas sobre Y cuando debes preguntar sobre X: en lugar de cómo usar y entender. una expresión regular, la pregunta debería ser qué herramienta se utiliza para administrar las rutas.

En lugar de rodar su propio código, use el código ya escrito que viene con el lenguaje:

 str = "abc/def/ghi.rb" File.basename(str) # => "ghi.rb" File.dirname(str) # => "abc/def" File.split(str) # => ["abc/def", "ghi.rb"] 

La razón por la que desea aprovechar el código integrado de File es que tiene en cuenta la diferencia entre los delimitadores de directorio en los sistemas operativos * nix-style y Windows. En el inicio, Ruby verifica el sistema operativo y establece la constante de File::SEPARATOR en lo que necesita el sistema operativo:

 File::SEPARATOR # => "/" 

Si su código se mueve de un sistema a otro, seguirá funcionando si utiliza los métodos incorporados, mientras que el uso de una expresión regular se interrumpirá inmediatamente porque el delimitador será incorrecto.