Encontre e substitua usando expressões regulares

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:

  1. 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?
  2. 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

  • Não consigo editar sua resposta, mas acredito que você quis dizer :%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.
  • IIRC você pode usar \r em vez de ^M para obter novas linhas?

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.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *