
Estou escrevendo um script bash para gerar automaticamente alguns outros arquivos e preciso formatar algumas strings de uma determinada maneira. Especificamente, o último problema que estou tendo é a formatação de uma string que possui letras maiúsculas individuais e uma palavra que começa com letra maiúscula. Por exemplo:
O S D Settings
precisa se tornarOSD Settings
Eu tenho um comando sed que remove o primeiro espaço, mas também exclui o "D" (ou seja, O S D Settings
-> OS Settings
). Este comando é:
O S D Settings | sed 's/ \([A-Z]\)* \(A-Za-z]*\)/\1/g'
Alguém sabe como excluir os espaços entre as letras maiúsculas individuais sem perder nenhuma letra?
Responder1
Isso cuida de nomes como A B Chadwick
eA B C D'Souza
Textos como A B cde
e A B CDE
não são modificados.
Ele usa dois caracteres nulos temporários \x00
para marcar alterações (por nome) à medida que avança em uma linha, removendo espaços.
:N
e :S
sãoramificar pararótulos (qualquer nome serve)
t
e b
são instruções de ramificação.
t
ramifica após uma substituição bem-sucedida no s/../../
comando anterior.
b
ramos incondicionalmente.
sed -r ":N # loop per name
/(\<[A-Z]\> )+[A-Z][a-z']/{ # line needs action
s/((\<[A-Z]\> )+)([A-Z][a-z'])/\x00\1\x00\3/ # add \x00 markers
:S # loop per space
s/(\x00[A-Z]+) (\<[A-Z]\>)/\1\2/ # delete a space
t S # any more spaces?
b N # any more names?
}; s/\x00//g" # remove \x00
Responder2
É complicado com sed
, mas se perl
estiver tudo bem, você pode fazer desta maneira
echo O S D Settings | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
Isso é difícil sed
porque não suporta afirmações antecipadas.
Testes:
echo O S D | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D Settings | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D. | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo One O DDE T. S Asdf Q R Tee | perl -p -e 's/(\b[A-Z]) (?=.([^\w]|$))/$1/g'
echo O S D\ | perl -p -e 's/([A-Z]) (?=.([^\w]|$))/$1/g'
Se você quiser uma solução desleixada sed
, tente
echo O S D Settings | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
O que funciona para sua amostra, mas falhará em outros casos.
Testes:
echo O S D | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D Settings | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D. | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo One O DDE T. S Asdf Q R Tee | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
echo O S D\ | sed -e 's/ \([A-Z]\) \([A-Z] \)/\1\2/g'
Responder3
Isso pode funcionar para você:
echo "O S D Settings and B T W and A B C D'Souza too F Y I" |
sed ':a;s/\(\<[[:upper:]]\>\) \(\<[[:upper:]]\>\([^'\'']\|$\)\)/\1\n\2/g;ta;s/\n//g'
OSD Settings and BTW and ABC D'Souza too FYI
Explicação:
Use um caractere que não exista na string original para substituir os espaços que você deseja excluir e, em seguida, exclua o caractere escolhido em toda a string. \n
é um bom candidato, pois não pode existir normalmente porque é usado pelo sed como delimitador de linha.
Responder4
Acabei usando apenas sed com pipes para obter uma declaração que seja fácil de entender:
echo O S D Settings | sed 's/\([A-Z][^ ]\)/_\1/g' | sed 's/ //g' | sed 's/_/ /g'
Tudo o que isso faz é substituir os espaços que não quero pelo sublinhado e depois excluí-los. Obrigado por todas as respostas!