2012-04-19 10 views
8

Sto cercando una versione più specifica del comando :sort u, che rimuoverà tutte le righe duplicate da un file. Sto lavorando con un csv e voglio rimuovere tutte le righe in cui la seconda voce della colonna ha un duplicato. Un esempio dovrebbe chiarire:: ordina u - ma solo su una colonna in un csv?

a,1,b 
g,1,f 
c,1,x 
i,2,l 
m,1,k 
o,2,p 
u,1,z 

comando sort dovrebbe produrre:

a,1,b 
i,2,l 

nota: le righe specifiche che vengono tenuti non sono importanti, purché dopo l'ordinamento delle voci 2a colonna sono tutti unici

Quale comando vim produrrà l'output sopra?

Grazie!

+1

Perché questo deve essere fatto in 'vim'? Devo pensare che usare un vero parser CSV per fare il lavoro sarebbe più facile. (A meno che tu non sia sicuro che i tuoi input non avranno "," incorporati in valori con virgolette o escape in stile backslash ...) – sarnold

+2

Non * deve * essere fatto in vim; Ti sto chiedendo come lo faresti vim. Posso pensare a molti altri modi per farlo ... ma sto cercando una soluzione vim. – Jonah

risposta

10

Poiché non è possibile ottenere la trasformazione sotto la domanda in una corsa del comando :sort, considerarla come una procedura in due passaggi.

Il primo passaggio consiste nell'ordinamento delle righe in base ai valori della seconda colonna separata da virgola. Per fare ciò, possiamo usare il comando :sort che passa un'espressione regolare che corrisponde alla prima colonna e alla seguente virgola di separazione. Come :sort confronta il testo che inizia subito dopo la corrispondenza del modello specificato su ciascuna riga, ci fornisce l'ordine di ordinamento desiderato.

:sort/^[^,]*,/ 

Per confrontare i valori numericamente, non lessicograficamente, utilizzare il flag n:

:sort n/^[^,]*,/ 

La seconda fase prevede che attraversa le linee filtrate e rimuovendo tutti tranne uno tra quelli con la stessa valore nella seconda colonna. È comodo per costruire la nostra implementazione sul comando :global che esegue un comando Ex su linee che corrispondono a un determinato modello. Per definizione, una riga può essere eliminata se contiene lo stesso valore nella seconda colonna come nella riga successiva. Questa formalizzazione (accompagnato con l'ipotesi iniziale che le virgole non possono verificarsi in valori di colonna) ci dà il seguente schema:

^[^,]*,\([^,]*\),.*\n[^,]*,\1,.* 

Quindi, se corriamo il comando :delete su ogni riga che soddisfa questo schema, da cima a in basso, avremo una sola riga per ogni valore distinto nella seconda colonna .

:g/^[^,]*,\([^,]*\),.*\n[^,]*,\1,.*/d_ 

Entrambe le fasi possono essere combinati in un unico comando Ex,

:sort/^[^,]*,/|g/^[^,]*,\([^,]*\),.*\n[^,]*,\1,.*/d_ 
+0

whoa, che funziona davvero. potresti abbattere quello che sta succedendo? – Jonah

+1

spiegazione eccellente. tyvm. – Jonah

1
:sort /\([^,]*,\)\{1}/ 
:g/\%(\%([^,]*,\)\{1}\1.*\n\)\@<=\%([^,]*,\)\{1}\([^,]*\)/d 

Ordina colonna con indice 1. secondo riscontrare ogni linea whos indice di colonna 1 partite righe successive colonna indice 1 ed eliminarlo.

indice di colonna è il 1 nel {1}. è ripetuto 3 volte.

+0

oh, è più o meno lo stesso della risposta di ib. non si rendeva conto al momento. mantenendo dovuto alla differenza di parametro indice colonna –

+0

Esatto. L'idea è praticamente la stessa, tranne che il tuo modello sembra indietro, mentre il mio guarda avanti (è più semplice). –

+0

Tom, grazie anche per la tua risposta – Jonah

0

utilizzando seconda colonna

(visual + !sort) 

usando terza colonna

sort -k 3 

o

:sort /.*\%3v/ 

Oppure

select the lines you wish to sort using the Capital V command. Then enter 
!sort -k 3n 

o saltare le prime due parole in ciascuna linea e ordinare con quanto segue:

:%sort /^\S\+\s\+\S\+\s\+/ 

o

ordina per lastest colonna

:%sort /\<\S\+\>$/ r 

O utilizzare un altro programma, come MS Office, oppure OPENOFFICE

Problemi correlati