sed: Solução portátil para combinar com “qualquer caractere, exceto nova linha”

1

Eu posso corresponder a nova linha por \n :

echo "one
two" | sed 'N;s/\n/_/g'

No GNU sed , posso usar [^\n] para corresponder a qualquer caractere, exceto nova linha:

echo "one
two" | sed 'N;s/[^\n]/_/g'

Isso é muito útil, mas viola o POSIX. Outras versões de sed respondem corretamente a __n______

A mesma coisa com o caractere de tabulação, mas lá eu posso contornar usando um caractere de tabulação real, precedido por ctrl-v. Mas isso não funciona para a nova linha:

echo "one
two" | sed 'N;s/[^
]/_/g'

me dá unbalanced brackets .

Usar [^[:cntrl:]] só funciona enquanto não houver outros caracteres de controle que eu queira corresponder.

Então, qual é a maneira correta de combinar qualquer caractere, exceto nova linha no POSIX sed ?

    
por Philippos 01.05.2017 / 12:15

3 respostas

1

Na verdade, existe uma maneira muito interessante de lidar com esse cenário na forma regular sed : interchange newline com algum caractere regular, digamos, _ depois, faça o [^ _] e, em seguida, retorne. Eu estava querendo postar uma solução para um problema que surgiu, mas estava com preguiça de postar, mas agora, deixe-me colocar aqui:

sed -e '
   /./!b

   :loop
      $q; N
   /\n$/bloop

   h

   /\ncreate table/!{
      s/\(.*\)\n.*//p
      g;s/.*\(\n\)//;D
   }

   g

   y/\n_/_\n/
      s/^[^_]*/test/
   y/\n_/_\n/

' input.data

Declaração do problema para a solução acima.

    
por 01.05.2017 / 12:30
1

Talvez eu não tenha entendido sua pergunta corretamente, mas vou me arriscar a responder.

Se você quiser corresponder tudo, exceto a nova linha, um ponto de regex simples . faz exatamente isso: corresponder qualquer caractere, exceto novas linhas.

Vamos experimentá-lo com um non gnu sed:

$ cat file5
home
help
variables
compatibility

$ sed 's/./_/g' file5
____
____
_________
_____________

$ echo "one
two
three
four" |sed 's/./_/g'
___
___
_____
____

A propósito, seu primeiro exemplo de sed:

echo "one
two" | sed 'N;s/\n/_/g'

corresponde apenas à próxima nova linha, não a todas as novas linhas:

$ echo "one
> two
> three
> four" |sed 'N;s/\n/_/g'
one_two
three_four
    
por 01.05.2017 / 13:56
1

Você pode usar a expressão de parênteses [[:alnum:][:punct:][:blank:]] :

echo "one
two" | sed 'N;s/[[:alnum:][:punct:][:blank:]]/_/g'

Saídas:

___
___

O [:alnum:] corresponde a todos os caracteres alfanuméricos, [:punct:] corresponde a todas as pontuações e [:blank:] corresponde a todos os espaços brancos horizontais. Todo o espaço em branco vertical é deixado de fora e não é correspondido.

Veja o on-line sed demo .

    
por 19.03.2019 / 20:02