Come 'rilasciare' / cancellare i caratteri davanti a una stringa?


13

Ho una stringa che vorrei manipolare. La stringa è H08W2345678come sarei in grado di manipolarla in modo che l'output sia giusto W2345678?

Allo stesso modo, se volessi eliminare gli ultimi 4 caratteri in H08W2345678modo da ottenere H08W234come farei?


1
Esistono molti modi per manipolare le stringhe. C'è un motivo specifico per l'utilizzo sed?
don_crissti,

@don_crissti Nessun motivo, a parte la mancanza di esperienza. Eventuali alternative sono benvenute ...
3kstc

@don_crissti, la storia: da un file CSV filtrato, prendo uno dei parametri da una linea che è H08W2345678e devo manipolarlo su W2345678Questo valore con altri dati verrà inserito in una e-mail inviata. La posta elettronica verrà effettuata con cron.
3kstc,

@don_crissti awkit. Creo un array e poi modifico ciascuno degli elementi all'interno dell'array (tutti in modo diverso - ovvero cambio il timpoimp Epoch in secondi a una data ecc.)
3kstc

2
Puoi fare cose del genere con awk:printf %s\\n "XX,H08W2345678,YY" | awk -F, '{print substr($2, 4); print substr($2, 1, length($2)-4)}'
don_crissti

Risposte:


19

Basta usare bash (o da ksh93dove proviene quella sintassi o zsh):

string="H08W2345678"

echo "${string:3}"
W2345678

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

Vedi il wiki di Wooledge per ulteriori informazioni sulla manipolazione delle stringhe .


Ciò richiede bash 4.2 o successivo. Vedi questa vecchia copia del Manuale di riferimento di Bash, Sezione 3.5.3, '' Espansione dei parametri della shell '' o la risposta dei pulcini qui per vedere il vecchio vincolo ("la lunghezza deve essere valutata con un numero maggiore o uguale a zero"); ... (proseguendo)
Scott,

(Proseguendo) ... vedi i cambiamenti di Bash (nel Wiki di Bash Hackers) (scorri verso il basso fino alla fine della sezione) o consulta le notizie presso l'organizzazione Technology Infrastructure Services della Case Western Reserve University (cerca "aggiunto a bash-4.2" e quindi scorrere verso il basso fino a “q.”) per vedere la revisione. ... ... ... ...  "${string:0:${#string}-4}" funziona in bash versione 4.1 purché la lunghezza $stringsia di almeno 4
Scott

PS Questo soffocerà anche su stringhe come abc-e, dove, quando lasci cadere i primi tre caratteri, ti rimane -e(perché echo -enon fa quello che vorresti).
Scott,

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

sed 's/^.\{3\}//'troverà i primi tre caratteri ^.\{3\}e li sostituirà con uno spazio vuoto. Qui ^.corrisponderà a qualsiasi carattere all'inizio della stringa ( ^indica l'inizio della stringa) e \{3\}corrisponderà esattamente al modello precedente 3 volte. Quindi, ^.\{3\}abbinerà i primi tre personaggi.

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

Allo stesso modo, sed 's/.\{4\}$//'sostituirà gli ultimi quattro caratteri con uno spazio vuoto ( $indica la fine della stringa).


1
Potresti spiegare per favore 's/^.\{3\}//'e 's/.\{4\}$//'come sto ancora imparando sed, molte grazie
3kstc

@ 3kstc: controlla le modifiche
heemayl

1
Per pochi personaggi, userei ...al posto del .\{3\}dato (per me) è più facile da leggere: sed -e 's/^...//' -e 's/....$//' o in una sola espressione con alternanza: sed -r 's/^...|....$//g'. Se ci fossero più di pochi caratteri da eliminare, allora userei l' /.\{17}\/espressione invece di /.............../.
Johnny,

Questo si comporterà male se la stringa è -eo -n. Naturalmente, il significato di “far cadere gli ultimi 4 caratteri” non è definito per una stringa più breve di 4 caratteri, ma, se qualcuno ha voluto adattare questo far cadere il primo o l'ultimo un carattere, potrebbe esplodere.
Scott,

2

Se si dispone di un file in cui ogni riga è una stringa di undici caratteri (o qualsiasi altra cosa) che si desidera tagliare, sedè lo strumento da utilizzare. Va bene per manipolare una singola stringa, ma è eccessivo. Per una singola stringa, la risposta di Jason è probabilmente la migliore, se hai accesso a bash versione 4.2 o successiva. Tuttavia, le sintassi e sembrano essere uniche per bash (bene, bash, ksh93, mksh e zsh) - Non le vedo nelle Specifiche di base di The Open Group per il linguaggio di comando Shell . Se sei bloccato con una shell conforme a POSIX che non supporta l'espansione della sottostringa (estrazione), puoi usare${parameter:offset}${parameter:offset:length}

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

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

usando printfinvece di echoguardarti dalle stringhe come abc-e, dove, quando lasci cadere i primi tre caratteri, ti rimane -e (e echo -enon fa quello che vorresti).

E, se non stai usando affatto una shell della famiglia Bourne (o stai usando un sistema pre-POSIX antico), questi dovrebbero comunque funzionare:

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

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

Lo spazio iniziale aggiuntivo è quello di evitare problemi con valori di $string che sono effettivi exprgli operatori (ad esempio, +,  /,  indexo match) o opzioni (ad esempio,  --, --help--version).


@ Stéphane Chazelas: (1) Grazie per avermi ricordato una trappola che conoscevo circa 40 anni fa e che in qualche modo sono riuscito a dimenticare. (2) Ho sempre usato per risolvere questo con X; ad es expr "X$string" : 'X...\(.*\)'. IMO, è più facile da leggere e capire. C'è qualche problema con questo, o qualche motivo per preferire uno spazio? (3) Oggi ho imparato che expr + "$string" : '...\(.*\)'ora funziona. Non me lo ricordo più di 40 anni fa; è sufficientemente ampiamente usato per essere sicuro da raccomandare? (4) Ti sei perso una nota sulla risposta di Jasonwryan e una risposta negativa alla risposta di Heemayl.
Scott,

AFAIK, cioè expr +solo GNU (non funzionerà su Solaris né FreeBSD AFAICS). Uso lo spazio invece di x poiché è meno probabile che alcune exprimplementazioni abbiano operatori che iniziano con lo spazio che con xe anche perché è meno probabile che ci siano elementi di confronto che iniziano con lo spazio che con x. Ma poi mi rendo conto che probabilmente non è una buona scelta per il expr " $a" "<" " $b"confronto di stringhe poiché alcune implementazioni finiscono per fare un confronto numerico quando $a/ $bsembrano numeri. Forse expr "@@$a"...o expr "x $a"potrebbe essere più sicuro.
Stéphane Chazelas,

0

Con:

string="H08W2345678"

La corrispondenza di 3 o 4 caratteri sembra semplice (per la maggior parte delle shell):

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

Per le shell più vecchie (come la shell Bourne), utilizzare:

$ string=H08W2345678

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

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

Se è necessario un conteggio numerico di caratteri, utilizzare:

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

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

Naturalmente, quei regex funzionano anche con 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

Come 'rilasciare' / cancellare i caratteri davanti a una stringa?

Ho una stringa che vorrei manipolare. La stringa è H08W2345678 come potrei essere in grado di manipolarla in modo che l'output sia solo W2345678?

echo "H08W2345678" | cut -c 4-

Questo risponde solo a metà della domanda.
Kusalananda

Credo che il tuo downvote sia ingiusto. Questa metà risponde alla domanda che ho fatto quando ho cercato su Google Posix di rimuovere i primi caratteri e questa pagina è stata mostrata nei risultati di ricerca. Inoltre, questo titolo di pagina copre solo la metà esatta della domanda. Sono tornato e ho contribuito quando ho trovato la soluzione che mi piaceva - penso che per quel lavoro cutsia molto più elegante di qualsiasi altra cosa sia presente in questa pagina.
aexl
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.