Come trovare la posizione di un personaggio usando grep?


11

Devo identificare la posizione di un personaggio nella stringa usando il comando grep.

Esempio, la stringa è RAMSITALSKHMAN|1223333.

grep -n '[^a-zA-Z0-9\$\~\%\#\^]'

Come trovo la posizione di |nella stringa specificata?


deve essere con grep?
Braiam,

Risposte:


29

È possibile utilizzare -bper ottenere l'offset di byte, che è uguale alla posizione per il testo semplice (ma non per UTF-8 o simile).

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|'
14:|

In quanto sopra, uso l' -ainterruttore per dire a grep di usare l'input come testo; necessario quando si opera su file binari e l' -oopzione per stampare solo i caratteri corrispondenti.

Se vuoi solo la posizione, puoi usare grep per estrarre solo la posizione:

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' | grep -oE '[0-9]+'
14

Se ottieni un output strano, controlla se grep ha i colori abilitati. Puoi disabilitare i colori passando --colors=nevera grep o aggiungendo il prefisso grep al comando con un \(che disabiliterà tutti gli alias), ad esempio:

$ echo "RAMSITALSKHMAN|1223333" | grep -aob '|' --color=never | \grep -oE '^[0-9]+'
14

Per una stringa che restituisce più corrispondenze, esegui il pipe through head -n1per ottenere la prima corrispondenza.

Nota che io uso entrambi in quanto sopra e nota che quest'ultimo non funzionerà se grep è "aliasato" attraverso un eseguibile (script o altro), solo quando si usano gli alias.


3
Ora cerca 2;)
Izkata,

Grazie @Izkata, hai ragione. Ho aggiornato un po 'il mio post e ho aggiunto il cappello mancante ^:)
runejuhl,

1
Quale versione di grep hai usato? Ottengo 0:|come output-- perché 0 è la posizione in byte dell'inizio della riga in cui |si trova.
Alex,

@Alex GNU grep da Debian stirata: grep (GNU grep) 2.27. Stai forse usando OS X?
runejuhl,

11

Provare:

printf '%s\n' 'RAMSITALSKHMAN|1223333.' | grep -o . | grep -n '|'

produzione:

15:|

Questo ti darà la posizione con index based-1.


Non funziona :(
user82782

1
@ user82782: quale comando hai eseguito? Come sai che non ha funzionato?
cuonglm,

printf '%s\n' '|' | grep -o . | grep -n '|'stampe 1, non 0come previsto.
l0b0

1
@ l0b0: l'OP non dice che voleva l'indice base 0 o 1.
cuonglm

Intendo solo cosa si aspetterebbe uno sviluppatore di software.
l0b0

8

Se stai usando la shell , puoi usare operazioni puramente integrate senza la necessità di generare processi esterni come o :

$ str="RAMSITALSKHMAN|1223333"
$ tmp="${str%%|*}"
$ if [ "$tmp" != "$str" ]; then
> echo ${#tmp}
> fi
14
$ 

Questo utilizza un'espansione dei parametri per rimuovere tutte le occorrenze di |follow da qualsiasi stringa e salvarle in una variabile temporanea. È quindi solo una questione di misurare la lunghezza della variabile temporanea per ottenere l'indice di |.

Nota che ifsta controllando se |esiste assolutamente nella stringa originale. In caso contrario, la variabile temporanea sarà la stessa dell'originale.

Nota anche questo fornisce l'indice a base zero di |cui è generalmente utile quando si indicizzano stringhe bash. Tuttavia, se si richiede l'indice a base singola, è possibile eseguire questa operazione:

$ echo $((${#tmp}+1))
15
$ 

1
probabilmente la risposta migliore, questa sintassi è bella, così veloce e facile da usare quando ne capisci il significato, viva fino al
midollo

4

È possibile utilizzare la indexfunzione di awk per restituire la posizione in caratteri in cui si verifica la corrispondenza:

echo "RAMSITALSKHMAN|1223333"|awk 'END{print index($0,"|")}'
15

Se non ti dispiace usare la indexfunzione Perl , questo gestisce la segnalazione di zero, una o più occorrenze di un personaggio:

echo "|abc|xyz|123456|zzz|" | \
perl -nle '$pos=-1;while (($off=index($_,"|",$pos))>=0) {print $off;$pos=$off+1}'

Per motivi di leggibilità, solo, la pipeline è stata suddivisa su due righe.

Finché viene trovato il personaggio bersaglio, indexrestituisce un valore positivo basato su zero (0). Quindi, la stringa "abc | xyz | 123456 | zzz |" quando analizzato restituisce le posizioni 0, 4, 8, 15 e 19.


per questo uso, awk è più utile / facile di grep.
Archemar,

Questo stampa solo la prima posizione, non funzionerà con stringhe comeRAMSITALSKHMAN|1|223333
cuonglm

3

Possiamo anche farlo usando "corrispondenza expr" o "indice expr"

expr corrisponde a $ string $ sottostringa dove $ sottostringa è un RE.

echo `expr match "RAMSITALSKHMAN|1223333" '[A-Z]*.|'`

E sopra ti darà la posizione perché restituisce la lunghezza della sottostringa abbinata.

Ma per essere più specifici per la ricerca dell'indice:

mystring="RAMSITALSKHMAN|122333"
echo `expr index "$mystring" '|'`

Non ho abbastanza reputazione per commentare altrove. Personalmente mi è piaciuta la risposta data da @Gnouc. Tuttavia perché usare awk e renderlo complesso quando possiamo fare cose semplici usando 'expr'
bluefoggy

@kingsdeb è solo un suggerimento.
Avinash Raj,

@kingsdeb: Perché (1) le awksoluzioni possono essere banalmente modificate per riportare queste informazioni su ogni riga di un file (tutto ciò che devi fare è rimuovere il END, che non è mai stato veramente necessario, dalla risposta di JRFerguson, e Avinash Raj lo fa già) ; considerando che, per farlo con la exprsoluzione, è necessario aggiungere un ciclo esplicito (e la risposta di Gnouc non è facilmente adattabile per farlo, quello che vedo), e (2) le awksoluzioni possono essere adattate per riportare tutte le corrispondenze in ciascuna riga un po 'più facilmente della exprsoluzione (in effetti, anche Avinash Raj lo fa già).
G-Man dice "Ripristina Monica" il

Perché dovresti usare echo `...`qui?
Stéphane Chazelas,

Questo serve solo a mostrare l'output qui
bluefoggy

2

Un altro comando awk ,

$ echo 'RAMSITALSKHMAN|1223333'| awk 'BEGIN{ FS = "" }{for(i=1;i<=NF;i++){if($i=="|"){print i;}}}'
15

Impostando il separatore di campo come stringa nulla, awk trasforma il singolo carattere nel record come campi separati.


2

alcune alternative includono:

simile alla risposta di Gnouc, ma con la shell:

echo 'RAMSITALSKHMAN|1223333' |
tr -c \| \\n | 
sh

sh: line 15: syntax error near unexpected token `|
sh: line 15: `|'

con sede dcpossibilmente che si estende su più righe:

echo 'RAMSITALSKHMAN|1223333' |
sed 's/[^|]/1+/g;s/|/p/;1i0 1+' |dc

15

con $IFS...

IFS=\|; set -f; set -- ${0+RAMSITALSKHMAN|1223333}; echo $((${#1}+1))

Che vi dirà anche come quanti ci sono come ...

echo $(($#-1))
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.