Tenho um arquivo com vários padrões do usuário. Quero alterar parte do texto, mas estou tendo dificuldades chegando com um matcher e substituto. Usando o seguinte exemplo:
############################################################################### # 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
Eu “d gostaria de substituir # Trackpad: ...
com running "Trackpad: ..."
Resolvendo o problema, descobri algo usando um testador de regex:
/\n\n#\s(.*)/g
Se eu tentar usar isso no Vim, não funcionará para mim:
:/\n\n#\s(.*)/running "\1"/g
Acho que meu problema se resume a duas questões específicas:
- Como posso evitar a pesquisa de
\n
caracteres e, em vez disso, certifique-se de que#
não apareça no final do grupo de pesquisa? - Como posso usar grupos de captura de maneira eficaz?
Existem algumas respostas excelentes abaixo. É difícil escolher entre as três, no entanto, sinto que a resposta escolhida é a mais precisa para minha especificação original. Recomendo que você tente todas as três respostas com o arquivo real para ver como você se sente a respeito delas.
Resposta
Só para deixar claro… acredito que você pediu que isso fosse o resultado da substituição?
############################################################################### # 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
Nesse caso, recomendo o seguinte comando:
:%s/\n\n#\s\+\(.*\)/^M^Mrunning "\1"/
Explicação do padrão
:s/PATTERN/REPLACEMENT/
é o comando substitute . O sinal de porcentagem em :%s
faz com que funcione em todo o arquivo, e não apenas na linha atual.
O \n\n
diz que a linha de interesse deve ocorrer após uma linha em branco. Se você não se importasse com a linha em branco anterior, ^
seria o suficiente.
#\s\+
corresponde a um hash caractere seguido por um ou mais caracteres de espaço em branco. \(.*\)
captura todo o texto subsequente na linha.
Explicação do texto de substituição
^M^M
insere duas extremidades de linhas para substituir os \n\n
que estavam presentes no padrão. Caso contrário, o texto seria movido para o final da linha precedendo a linha em branco. Para digitar cada ^M
, pressione Ctrl-V Ctrl-M .
Em seguida, insira a string running
, seguida por tudo o que foi capturado entre parênteses entre aspas duplas.
Comentários
Resposta
Eu usaria algo como:
:s/^#\s\+\(.\{-}\):/running "\1":/
-
^#
para corresponder ao#
caractere ancorado no início da linha (responde à pergunta 1) -
\s\+
para corresponder a qualquer espaço em branco uma ou mais vezes -
\(
para iniciar um grupo (responde a pergunta 2) -
.\{-}\
para corresponder a qualquer caractere 0 ou mais vezes em um maneira não gananciosa ; isso é diferente de.*
porque tenta corresponder o mínimo possível, e não tanto quanto possível. Tente adicionar um:
caractere no comentário para ver por que isso é importante -
\)
para encerrar o subgrupo. -
:
corresponde a um literal:
Em seguida, substituímos isso pelo texto que você deseja e use \1
para se referir ao grupo que capturamos.
Eu descobri algo usando um testador de regex
A sintaxe da expressão regular é um pouco como a sintaxe do wiki: há vários deles, todos parecem iguais à primeira vista, nenhum deles é obviamente melhor do que qualquer outro, mas há muitas diferenças.
Hoje, as chamadas expressões regulares “compatíveis com Perl” são o padrão de fato na maioria das linguagens, mas as expressões regulares do Vim não compatível com expressões compatíveis com Perl! A sintaxe regexp do Vim remonta a pelo menos “70” s, quando Perl não existia.
Você pode ver isso com os subgrupos, onde você deve usar \(
e não (
(isso é compatível com a sintaxe POSIX “básica”, mas não com a sintaxe POSIX “estendida” mais comum ou sintaxe Perl).Você pode controlar isso adicionando o sinalizador \v
em um padrão (consulte :help /\v
para obter detalhes), isso o tornará “mais compatível”, mas não completamente (você ainda precisa usar .{-}
para correspondências não gananciosas, por exemplo)
Portanto, isso pode explicar por que usar “um testador de regex” quase funciona, mas não exatamente.
http://www.vimregex.com/ como uma boa visão geral / cheatsheet de regexps do Vim.
Comentários
- Ótima resposta, especialmente com why regex! = regex. Quanto à sua pesquisa e substituição, ‘ é um pouco complicado, pois o comentário pode ou não ter um
:
. Veja o arquivo completo para obter detalhes github.com/squarefrog/dotfiles/blob/master/osx/…
Resposta
Você pode:
- pesquisar linhas que não terminam em
#
::/[^#]$/
- substitua
#\s(.*)
no início de a linha:s/\v^#\s(.*)/running "\1"/
Para usar grupos, você precisa:
- escapar os colchetes para que eles se tornam parte da sintaxe regex:
\(.*\)
ou - use “magic” por começando a expressão com
\v
:s/\v...
Combinando:
:/[^#]$/s/\v^#\s(.*)/running "\1"/
Comentários
- Funciona de maneira brilhante, obrigado por incluir uma explicação do significado das tags em vez de apenas o texto que eu precisava escrever.
- Obrigado por deixar claro que os colchetes têm t o ser escapado para se tornar parte da sintaxe regex. Sempre tive problemas com grupos regex para fazê-los funcionar.
:%s/\v\n\n#\s+(.*)/^M^Mrunning "\1"/
(adicionou a ” mágica ” sinalizador). É realmente difícil escolher uma resposta correta para minha pergunta original, mas sinto que essa resposta é a mais próxima da minha resposta original esperada. É também o único que funciona em todo o arquivo sem a necessidade de selecionar um intervalo.\r
em vez de^M
para obter novas linhas?