2016-06-27 107 views
5

Sto riscontrando problemi nel tentativo di estrarre i separatori di migliaia da alcuni valori di valuta in un insieme di file. I valori "cattivi" sono delimitati da virgole e virgolette. Ci sono altri valori in là che sono < $ 1000 che non presentano alcun problema.sostituire migliaia separatori in csv con regex

Esempio di file esistente:

"12,345.67",12.34,"123,456.78",1.00,"123,456,789.12" 

Esempio di desiderava di file (migliaia separatori rimossi):

"12345.67",12.34,"123456.78",1.00,"123456789.12" 

ho trovato un'espressione regex per abbinare i numeri con i separatori che funziona grande, ma ho problemi con l'operatore -replace. Il valore di sostituzione mi confonde. Ho letto su $ & e mi chiedo se dovrei usarlo qui. Ho provato $ _, ma questo tira fuori TUTTE le mie virgole. Devo usare $ partite in qualche modo?

Ecco il mio codice:

$Files = Get-ChildItem *input.csv 
foreach ($file in $Files) 
    { 
     $file | 
     Get-Content | #assume that I can't use -raw 
     % {$_ -replace '"[\d]{1,3}(,[\d]{3})*(\.[\d]+)?"', ("$&" -replace ',','')} | #this is my problem 
     out-file output.csv -append -encoding ascii 
    } 
+2

Usa import-csv e quindi è possibile scorrere ciclicamente le righe e gli elementi, rimuovere le virgole da ciascun elemento, mentre si costruiscono nuove righe mentre si procede, quindi salvare le nuove righe nel file sovrascrivendole. –

risposta

3

Si può provare con questa espressione regolare:

,(?=(\d{3},?)+(?:\.\d{1,3})?") 

Vedi Live Demo o in PowerShell:

% {$_ -replace ',(?=(\d{3},?)+(?:\.\d{1,3})?")','' } 

Ma è di più sulla sfida che regex può portare. Per un lavoro corretto, usa la risposta @briantist che è il modo pulito per farlo.

+0

Questo ha funzionato come un CHAMP e mi ha spinto a leggere di più su cose come "affermazioni positive" e "gruppi lookahead". Grazie Thomas. – astraljack

2

vorrei usare una regex più semplice, e utilizzare i gruppi di acquisizione anziché l'intero cattura. Ho testato la seguente espressione regolare con il tuo input e non ho riscontrato problemi.

% {$_ -replace '([\d]),([\d])','$1$2' }

ad es. Trova tutte le virgole con un numero prima e dopo (in modo che le strane divisioni miste non contengano) e sostituisca interamente la virgola.

Questo avrebbe problemi se il tuo input ha uno scenario senza quel mix strano di citazioni e senza virgolette.

+1

Personalmente, adoro questa risposta. È possibile importare direttamente il file come testo, eseguire la regex replace e stamparlo come testo. Non c'è bisogno di convertire le cose in oggetti, quindi dovrebbe ridurre le spese generali. Si potrebbe anche fare un lookahead/lookbehind e saltare l'ultima parte della sostituzione. [Esempio RegEx101] (https: // regex101.com/r/nL2rM9/2) – TheMadTechnician

+1

Anche questo è grandioso. Ho pensato che sarebbe fallito con più separatori (ad esempio 123,456,789,12), ma funziona e ora vedo perché. – astraljack

5

Il commento di Tony Hinkle è la risposta: non usare regex per questo (almeno non direttamente sul file CSV).

Il CSV è valido, quindi è necessario analizzarlo come tale, lavorare sugli oggetti (modificare il testo se lo si desidera), quindi scrivere un nuovo CSV.

Import-Csv -Path .\my.csv | ForEach-Object { 
    $_ | ForEach-Object { 
     $_ -replace ',','' 
    } 
} | Export-Csv -Path .\my_new.csv 

(questo codice ha bisogno di lavoro, in particolare al centro come riga avrà ogni colonna come una proprietà, non è un array, ma una versione più completa del CSV farebbe che più facile da dimostrare)