2016-06-27 16 views
5

Występują problemy przy próbie wyciągnięcia separatorów tysięcy z niektórych wartości walutowych w zbiorze plików. "Złe" wartości są rozdzielane przecinkami i podwójnymi cudzysłowami. Są tam inne wartości, które wynoszą < $ 1000, które nie stanowią problemu.Zastępuje separatory tysięcy w CSV z regex

Przykład istniejącego pliku:

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

Przykład pożądane plików (tysiące separatorów usunięte):

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

I znaleziono regex ekspresji dla dopasowania liczby w separator, który działa doskonale, ale mam problem z operatorem -replace. Wartość zastępcza mnie myli. Czytałem o $ & i zastanawiam się, czy powinienem użyć tego tutaj. Próbowałem $ _, ale to wyciąga WSZYSTKIE moje przecinki. Czy muszę jakoś używać zapałek $?

Oto mój kod:

$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

Użyj import-csv, a następnie możesz przechodzić między wierszami i elementami, usuwać przecinki z każdego elementu, budując nowe wiersze, a następnie zapisywać nowe wiersze w pliku zastępującym. –

Odpowiedz

3

Można spróbować z tym regex:

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

Zobacz Live Demo lub w PowerShell:

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

Ale to jest więcej o wyzwanie, które może przynieść regex. Do prawidłowej pracy użyj odpowiedzi @briantist, która jest prostym sposobem na zrobienie tego.

+0

To zadziałało jak CHAMP i zachęciło mnie do przeczytania więcej o rzeczach takich jak "pozytywne twierdzenia" i "grupy z uprzedzeniami". Dzięki, Thomas. – astraljack

2

użyłbym prostsze regex i używać zamiast grupy przechwytywania całego przechwytywania. Przetestowałem następujące wyrażenie regularne z wprowadzonymi danymi i nie znalazłem żadnych problemów.

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

np. Znajdź wszystkie przecinki z numerem przed i po (tak, aby dziwne mieszane podziały nie mają znaczenia) i zastąp kroplę całkowicie.

To miałoby problem, jeśli dane wejściowe zawierają scenariusz bez dziwnego mieszania ofert i bez cudzysłowów.

+1

Osobiście uwielbiam tę odpowiedź. Możesz prosto importować plik jako tekst, uruchamiać wyrażenie regularne i wyprowadzać je jako tekst. Nie trzeba konwertować obiektów na obiekty, dlatego powinno się zmniejszać narzut. Możesz nawet zrobić to z wyprzedzeniem/lookbehind i pominąć ostatnią część zamiennika. [Przykład RegEx101] (https: // regex101.com/r/nL2rM9/2) – TheMadTechnician

+1

To też jest świetne. Myślałem, że to się nie uda z wieloma separatorami (np. 123,456,789,12), ale działa i teraz rozumiem, dlaczego. – astraljack

5

Komentarz Tony Hinkle'a jest odpowiedzią: nie używaj w tym celu wyrażenia regularnego (przynajmniej nie bezpośrednio w pliku CSV).

Twój plik CSV jest ważny, więc powinieneś go sparsować, pracować nad obiektami (zmienić tekst, jeśli chcesz), a następnie napisać nowy plik CSV.

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

(kod ten wymaga pracy, a konkretnie w srodku jak rząd będzie mieć każdą kolumnę w postaci nieruchomości, a nie tablicy, ale pełniejszą wersją pliku CSV spowodowałoby, że łatwiej wykazać)