Encuentra y reemplaza usando expresiones regulares


26

Tengo un archivo con un montón de valores predeterminados de usuario. Quiero cambiar parte del texto, pero estoy luchando para encontrar un comparador y un sustituto. Usando el siguiente ejemplo:

###############################################################################
# Trackpad, mouse, keyboard, Bluetooth accessories, and input                 #
###############################################################################

# Trackpad: enable tap to click for this user and for the login screen
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true

Me gustaría reemplazar # Trackpad: ...conrunning "Trackpad: ..."

Desglosando el problema, se me ocurrió algo usando un probador de expresiones regulares:

/\n\n#\s(.*)/g

Si intento usar esto en Vim, no funciona para mí:

:/\n\n#\s(.*)/running "\1"/g

Supongo que mi problema se reduce a dos preguntas específicas:

  1. ¿Cómo puedo evitar buscar \ncaracteres y, en cambio, asegurarme de #que no aparezca al final del grupo de búsqueda?
  2. ¿Cómo puedo usar efectivamente los grupos de captura?

Hay algunas respuestas geniales a continuación. Es difícil elegir entre los tres, sin embargo, creo que la respuesta elegida es la más precisa para mi especificación original. Le recomiendo que pruebe las tres respuestas con el archivo real para ver cómo se siente al respecto.

Respuestas:


18

Para que quede claro ... ¿Creo que pediste que esto fuera el resultado de la sustitución?

###############################################################################
# Trackpad, mouse, keyboard, Bluetooth accessories, and input                 #
###############################################################################

running "Trackpad: enable tap to click for this user and for the login screen"
defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true

En ese caso, recomiendo el siguiente comando:

:%s/\n\n#\s\+\(.*\)/^M^Mrunning "\1"/

Explicación del patrón.

:s/PATTERN/REPLACEMENT/es el comando sustituto . El inicio de sesión porcentual :%shace que funcione en todo el archivo, en lugar de solo la línea actual.

El \n\ndice que la línea de interés debe ocurrir después de una línea en blanco. Si no le importó la línea en blanco anterior, entonces ^sería suficiente.

#\s\+coincide con un carácter hash seguido de uno o más caracteres de espacio en blanco. \(.*\)captura todo el texto posterior en la línea.

Explicación del texto de reemplazo.

^M^Minserta dos extremos de líneas para reemplazar los \n\nque estaban presentes en el patrón. De lo contrario, el texto se movería al final de la línea que precede a la línea en blanco. Para escribir cada uno ^M, presione Ctrl-V Ctrl-M.

Luego, inserte la cadena running, seguida de lo que se haya capturado entre paréntesis entre comillas dobles.


No puedo editar su respuesta, pero creo que se refería a usted :%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/(agregó la bandera "mágica"). Es realmente difícil elegir una respuesta correcta para mi pregunta original, pero creo que esta respuesta es la más cercana a mi respuesta original esperada. También es el único que funciona en todo el archivo sin necesidad de seleccionar un rango.
squarefrog

1
¿IIRC puede usar en \rlugar de ^Mobtener nuevas líneas?
muru

11

Yo usaría algo como:

:s/^#\s\+\(.\{-}\):/running "\1":/
  • ^#para que coincida con el #carácter anclado al comienzo de la línea (esto responde a la pregunta 1)
  • \s\+ para que coincida con cualquier espacio en blanco una o más veces
  • \( para comenzar un grupo (esto responde a la pregunta 2)
  • .\{-}\para emparejar cualquier personaje 0 o más veces de una manera no codiciosa ; esto es diferente .*en el sentido de que trata de igualar lo menos posible y no tanto como sea posible. Intenta agregar un :personaje en el comentario para ver por qué esto importa
  • \) para finalizar el subgrupo.
  • : coincide con un literal :

Luego reemplazamos esto con el texto que desea, y lo usamos \1para referirnos al grupo que capturamos.

Se me ocurrió algo usando un probador de expresiones regulares

La sintaxis de expresión regular es un poco como la sintaxis wiki: hay un montón de ellas, todas se parecen a simple vista, ninguna de ellas es obviamente mejor que ninguna otra, pero hay muchas diferencias.

Hoy, las llamadas expresiones regulares "compatibles con Perl" son las predeterminadas de facto en la mayoría de los idiomas, ¡pero las expresiones regulares de Vim no son compatibles con las expresiones compatibles con Perl! La sintaxis de Vim regexp se remonta al menos a los años 70, cuando Perl ni siquiera estaba presente.

Puede ver esto con los subgrupos, donde debe usar \(y no ((esto es compatible con la sintaxis 'básica' POSIX, pero no con la sintaxis 'extendida' POSIX más común o la sintaxis Perl). Puede controlar esto agregando la \vbandera en un patrón (ver :help /\vpara más detalles), esto lo hará "más compatible", pero no completamente (todavía tiene que usar .{-}para coincidencias no codiciosas, por ejemplo)

Entonces, esto podría explicar por qué el uso de "un probador de expresiones regulares" casi, pero no del todo, funciona.

http://www.vimregex.com/ como una buena descripción / cheatsheet de Vim regexps.


1
Gran respuesta, especialmente con por qué regex! = Regex. En cuanto a su búsqueda y reemplazo, es un poco complicado ya que el comentario puede o no tener un :. Vea el archivo completo para más detalles github.com/squarefrog/dotfiles/blob/master/osx/…
squarefrog

8

Usted puede:

  • buscar líneas que no terminen en #::/[^#]$/
  • reemplazar #\s(.*)al comienzo de la línea:s/\v^#\s(.*)/running "\1"/

Para usar grupos, necesita:

  • escapar de los corchetes para que formen parte de la sintaxis de expresiones regulares: \(.*\)o
  • use "magia" comenzando la expresión con \v:s/\v...

Combinándolo:

:/[^#]$/s/\v^#\s(.*)/running "\1"/

1
Esto funciona de manera brillante, gracias por incluir una explicación de lo que significan las etiquetas en lugar de solo el texto que necesitaba escribir.
squarefrog

Gracias por dejar en claro que los corchetes deben escaparse para formar parte de la sintaxis de expresiones regulares. Siempre tuve un problema con los grupos de expresiones regulares para hacerlos trabajar.
Adama
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.