Tengo un archivo con un montón de valores predeterminados del usuario. Quiero cambiar parte del texto, pero estoy luchando creando un comparador y un reemplazador. 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: ...
con running "Trackpad: ..."
Resolviendo el problema, se me ocurrió algo usando un probador de expresiones regulares:
/\n\n#\s(.*)/g
Si intento usar esto en Vim, no me funciona:
:/\n\n#\s(.*)/running "\1"/g
Creo que mi problema se reduce a dos preguntas específicas:
- ¿Cómo puedo evitar buscar
\n
caracteres y, en cambio, asegurarme de que#
no aparezca al final del grupo de búsqueda? - ¿Cómo puedo utilizar eficazmente los grupos de captura?
A continuación, encontrará algunas respuestas excelentes. 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.
Respuesta
Para que quede claro… ¿Creo que solicitó que este sea 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 signo de porcentaje en :%s
hace que funcione en todo el archivo, en lugar de solo en la línea actual.
El \n\n
dice que la línea de interés debe aparecer después de una línea en blanco. Si no le importaba la línea en blanco anterior, entonces ^
sería suficiente.
#\s\+
coincide con un hash carácter seguido de uno o más caracteres de espacio en blanco. \(.*\)
captura todo el texto subsiguiente en la línea.
Explicación del texto de reemplazo
^M^M
inserta dos extremos de líneas para reemplazar los \n\n
que estaban presentes en el patrón. De lo contrario, el texto se movería al final de la línea antes de la línea en blanco. Para escribir cada ^M
, presione Ctrl-V Ctrl-M .
Luego, inserte la cadena running
, seguida de lo que fue capturado entre paréntesis entre comillas dobles.
Comentarios
Responder
Yo usaría algo como:
:s/^#\s\+\(.\{-}\):/running "\1":/
-
^#
para que coincida con el carácter#
anclado al principio 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 iniciar un grupo (esto responde a la pregunta 2) -
.\{-}\
para que coincida con cualquier carácter 0 veces o más en un forma no codiciosa ; esto es diferente de.*
en que trata de hacer coincidir lo menos posible y no tanto como sea posible. Intente agregar un carácter:
en el comentario para ver por qué esto es importante -
\)
para finalizar el subgrupo. -
:
coincide con un literal:
Luego lo reemplazamos con el texto que desee y use \1
para referirse 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 la vista, ninguna es obviamente mejor que cualquier otro, pero hay muchas diferencias.
Hoy en día, las expresiones regulares «compatibles con Perl» son las predeterminadas de facto en la mayoría de los lenguajes, pero las expresiones regulares de Vim no compatible con expresiones compatibles con Perl. La sintaxis de Vim regexp se remonta al menos a los «70», cuando Perl ni siquiera existía.
Puede ver esto con los subgrupos, donde debe usar \(
y no (
(esto es compatible con la sintaxis «básica» de POSIX, pero no con la sintaxis «extendida» de POSIX más común o la sintaxis de Perl).Puede controlar esto agregando el indicador \v
en un patrón (consulte :help /\v
para obtener más detalles), esto lo hará «más compatible», pero no completamente (aún debe usar .{-}
para coincidencias no codiciosas, por ejemplo)
Entonces, esto podría explicar por qué usar «un probador de expresiones regulares» casi, pero no del todo, funciona.
http://www.vimregex.com/ como una buena descripción general / hoja de trucos de las expresiones regulares de Vim.
Comentarios
- Excelente respuesta, especialmente con por qué regex! = regex. En cuanto a su búsqueda y reemplazo, ‘ es un poco complicado ya que el comentario puede tener o no un
:
. Consulte el archivo completo para obtener más detalles github.com/squarefrog/dotfiles/blob/master/osx/…
Responder
Puede:
- buscar líneas que no terminen en
#
::/[^#]$/
- reemplace
#\s(.*)
al comienzo de la línea:s/\v^#\s(.*)/running "\1"/
Para usar grupos, debe:
- escapar de los corchetes para que pasan a formar parte de la sintaxis de expresiones regulares:
\(.*\)
, o - use «magic» por comenzando la expresión con
\v
:s/\v...
Combinándola:
:/[^#]$/s/\v^#\s(.*)/running "\1"/
Comentarios
- 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.
- Gracias por dejar en claro que los corchetes no o ser de escape para formar parte de la sintaxis de expresiones regulares. Siempre tuve problemas con los grupos de expresiones regulares para hacerlos funcionar.
:%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/
(se agregó la » magic » bandera). Es muy 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.\r
en lugar de^M
para obtener nuevas líneas?