Como 'soltar' / excluir caracteres na frente de uma string?


12

Eu tenho uma string que gostaria de manipular. A string é H08W2345678como eu seria capaz de manipulá-la para que a saída seja justa W2345678?

Da mesma forma, se eu quisesse soltar os últimos 4 caracteres H08W2345678para que eu entendesse, H08W234como faria isso?


1
Existem muitas maneiras de manipular seqüências de caracteres. Existe um motivo específico para o uso sed?
don_crissti

@don_crissti Sem motivo, além da falta de experiência. Todas as alternativas são bem-vindos ...
3kstc

@don_crissti, a história: de um arquivo CSV filtrado, eu pego um dos parâmetros de uma linha que é H08W2345678e precisa manipulá-lo para W2345678Este valor com outro dado será colocado em um email enviado. Este e-mail será realizado com o cron.
3kstc 7/04

@don_crissti awking. I criar uma matriz e em seguida modificar cada um dos elementos dentro da matriz (todos de maneira diferente - ou seja, alterar o Epoch timestaimp em segundos para uma data, etc.)
3kstc

2
Você pode fazer coisas assim com awk:printf %s\\n "XX,H08W2345678,YY" | awk -F, '{print substr($2, 4); print substr($2, 1, length($2)-4)}'
don_crissti

Respostas:


18

Apenas usando o bash (ou de ksh93onde vem essa sintaxe ou zsh):

string="H08W2345678"

echo "${string:3}"
W2345678

echo "${string:0:-4}"
H08W234

Veja o wiki do Wooledge para mais informações sobre manipulação de strings .


Isso requer o bash 4.2 ou superior. Veja esta cópia antiga do Bash Reference Manual, Seção 3.5.3, '' Shell Parameter Expansion '' ou a resposta dos pintinhos aqui para ver a restrição antiga (“o comprimento deve ser avaliado para um número maior ou igual a zero”.); ... (continua)
Scott

(Continua) ... consulte Alterações do Bash (no Wiki do Bash Hackers) (role para baixo na parte inferior da seção) ou receba notícias da organização Technology Infrastructure Services da Case Western Reserve University (procure por "added to bash-4.2" e role para baixo até “q.”) para ver a revisão. ... ... ... ...  "${string:0:${#string}-4}" funciona em bash versão 4.1, enquanto o comprimento de $stringpelo menos 4.
Scott

PS Isso também engasga com seqüências de caracteres como abc-e, onde, quando você solta os três primeiros caracteres, você fica com -e(porque echo -enão faz o que você gostaria).
Scott

8
$ echo "H08W2345678" | sed 's/^.\{3\}//'
W2345678

sed 's/^.\{3\}//'encontrará os três primeiros caracteres por ^.\{3\}e substituirá por em branco. Aqui ^.corresponderá qualquer caractere no início da sequência ( ^indica o início da sequência) e \{3\}corresponderá ao padrão anterior exatamente 3 vezes. Então, ^.\{3\}irá coincidir com os três primeiros caracteres.

$ echo "H08W2345678" | sed 's/.\{4\}$//'
H08W234

Da mesma forma, sed 's/.\{4\}$//'substituirá os últimos quatro caracteres por branco ( $indica o final da sequência).


1
Poderia explicar o 's/^.\{3\}//'e 's/.\{4\}$//'como eu ainda estou aprendendo sed, muito obrigado
3kstc

@ 3kstc: Verifique as edições
heemayl 7/15

1
Por apenas alguns caracteres, eu usaria ...em vez de .\{3\}uma vez (para mim) é mais fácil de ler: sed -e 's/^...//' -e 's/....$//' ou numa única expressão com alternância: sed -r 's/^...|....$//g'. Se houvesse mais do que alguns caracteres para excluir, usaria a /.\{17}\/expressão em vez de /.............../.
Johnny

Isso se comportará mal se a string for -eou -n. Claro, o significado de “soltar os últimos 4 caracteres” é indefinido para uma cadeia menor que 4 caracteres, mas, se alguém queria adaptar este deixar cair a primeira ou a última de um personagem, que poderia explodir.
Scott

2

Se você possui um arquivo no qual cada linha é uma cadeia de onze caracteres (ou o que for) que você deseja cortar, sedé a ferramenta a ser usada. É bom manipular uma única string, mas é um exagero. Para uma única sequência, a resposta de Jason é provavelmente a melhor, se você tiver acesso ao bash versão 4.2 ou superior. No entanto, as sintaxes e parecem exclusivas do bash (bem, bash, ksh93, mksh e zsh) - não as vejo nas Especificações Básicas do Grupo Aberto para a Linguagem de Comando do Shell . Se você estiver preso com um shell compatível com POSIX que não suporta expansão de substring (extração), poderá usar${parameter:offset}${parameter:offset:length}

$ printf "%s\n" "${string#???}"
W2345678

$ printf "%s\n" "${string%????}"
H08W234

usando em printfvez de echopara se proteger de seqüências de caracteres como abc-e, onde, quando você solta os três primeiros caracteres, você fica com -e (e echo -enão faz o que deseja).

E, se você não estiver usando um shell da família Bourne (ou estiver usando um sistema antigo pré-POSIX), eles ainda deverão funcionar:

$ expr " $string" : ' ...\(.*\)'
W2345678

$ expr " $string" : ' \(.*\)....'
H08W234

O espaço à esquerda extra é para evitar problemas com valores de $string que são reais exproperadores (por exemplo, +,  /,  indexou match) ou opções (por exemplo,  --, --helpou  --version).


@ Stéphane Chazelas: (1) Obrigado por me lembrar de uma armadilha que eu conhecia há 40 anos e de alguma forma consegui esquecer. (2) eu sempre costumava resolver isso com X; por exemplo expr "X$string" : 'X...\(.*\)',. Na IMO, é mais fácil ler e entender. Existe algum problema com isso ou algum motivo para preferir um espaço? (3) Hoje eu aprendi que expr + "$string" : '...\(.*\)'agora funciona. Não me lembro disso de 40 anos atrás; é suficientemente utilizado para ser seguro recomendar? (4) Você perdeu uma nota sobre a resposta de jasonwryan e uma picareta sobre a resposta de heemayl.
Scott

AFAIK, que expr +é apenas GNU (não funcionará no Solaris nem no FreeBSD AFAICS). Uso espaço em vez de x, pois é menos provável que alguma exprimplementação tenha operadores que iniciam com espaço do que com xe também porque é menos provável que haja elementos de intercalação que começam com espaço do que com x. Mas então percebo que provavelmente não é uma boa opção para expr " $a" "<" " $b"comparação de cadeias, pois algumas implementações acabam fazendo comparação numérica quando $a/ $bparecem números. Talvez expr "@@$a"...ou expr "x $a"possa ser mais seguro.
Stéphane Chazelas

0

Com:

string="H08W2345678"

Combinar 3 ou 4 caracteres parece simples (para a maioria das conchas):

$ printf '%s\t%s\n' "${string#???}" "${string%????}"
W2345678      H08W234

Para as conchas mais antigas (como a concha Bourne), use:

$ string=H08W2345678

$ expr " ${string}" : " ...\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\)...." '
H08W234

Se for necessária uma contagem numérica de caracteres, use:

$ expr " ${string}" : " .\{3\}\(.*\)"
W2345678

$ expr " ${string}" : " \(.*\).\{4\}" '
H08W234

Obviamente, esses regex também funcionam com sed, awk e bash 3.0+:

$ echo "$string" | sed 's/^.\{3\}//'
W2345678

$ echo "$string" | sed 's/.\{4\}$//'
H08W234

$ echo "$string" | awk '{sub(/^.{3}/,"")}1'
W2345678

$ echo "$string" | awk '{sub(/.{4}$/,"")}1'
H08W234

$ r='^.{3}(.*)$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
W2345678

$ r='^(.*).{4}$'; [[ $a =~ $r ]] && echo "${BASH_REMATCH[1]}"
H08W234

-1

Como 'soltar' / excluir caracteres na frente de uma string?

Eu tenho uma string que gostaria de manipular. A string é H08W2345678, como eu seria capaz de manipulá-la para que a saída seja apenas W2345678?

echo "H08W2345678" | cut -c 4-

Isso responde apenas a metade da pergunta.
Kusalananda

Eu acredito que seu voto negativo é injusto. Essa metade responde à pergunta que eu fiz ao pesquisar no posix, removendo os primeiros caracteres e esta página apareceu nos resultados de pesquisa. Além disso, o título desta página cobre apenas a metade exata da questão. Voltei e contribuí quando encontrei a solução que eu gostava - acho que esse trabalho cuté muito mais elegante do que qualquer outra coisa nesta página.
Aexl
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.