2015-05-14 14 views

risposta

3

Adattare il codice "How to remove double quotes on specific column from CSV file using Powershell script":

$csv = 'C:\path\to\your.csv' 
(Get-Content $csv) -replace '(?m)"([^,]*?)"(?=,|$)', '$1' | 
    Set-Content $csv 

L'espressione regolare (?m)"([^,]*?)"(?=,|$) è la corrispondenza qualsiasi " + 0 or more non-commas + "prima una virgola o alla fine della riga (ottenuto con una positiva look-ahead e un'opzione multilinea (?m) che forza lo $ in modo che corrisponda a una nuova riga, non solo alla fine della stringa).

Vedi regex demo

+0

Grazie per tutto il tuo aiuto, Wiktor - Ho ripulito i miei commenti precedenti. Pensiero finale: puoi usare '(? M)' se usi 'Get-Content -Raw' (PSv3 +) per leggere l'intero file in una singola stringa, il che velocizzerà anche le cose. Tuttavia, per evitare una nuova riga finale, l'output deve essere scritto con 'Set-Content -NoNewline' - che è PSv5 +:' (Get-Content -Raw $ csv) -replace '(? M) "([^ ,] *?) "(? =, | $)", "$ 1" | Set-Content -NoNewline $ csv' – mklement0

1

Non so esattamente che cosa il resto dello script assomiglia. Prova qualcosa in questo senso anche se

(("bob","1234 Main St, New York, NY","cool guy") -split '"' | 
    ForEach-Object {IF ($_ -match ",") {'"' + $_ + '"' } ELSE {$_}}) -join "," 
0

Le risposte esistenti funzionano bene con l'ingresso del campione:

  • Wiktor Stribiżew's helpful answer, che identifica i campi doppi apici che non contengono , utilizzando un'espressione regolare, carica l'intero file di input nella memoria in primo luogo, che consente di sostituire il file di input con i risultati in una singola pipeline.
    Mentre questo è conveniente - e più veloce dell'elaborazione riga per riga - l'avvertenza è che potrebbe non essere un'opzione per file di input di grandi dimensioni.
  • markg's helpful answer, che suddivide le righe in campi per " caratteri., È un'alternativa per file di input di grandi dimensioni, poiché utilizza la pipeline per elaborare le righe di input una alla volta.
    (Di conseguenza, il file di input non può essere direttamente aggiornati con il risultato.)

Se generalizzare requisito del PO di gestire anche i campi con incorporati " caratteri., abbiamo bisogno di un approccio diverso:

I seguenti campi devono quindi mantenere la loro racchiudere i doppi apici:

  • (di necessità) Campi doppi apici con incorporati , caratteri .; per esempio..,
    "1234 Main St, New York, NY"
  • (necessariamente) campi doppio citato con incorporati " caratteri, che, per RFC 4180 deve essere sfuggito come "", cioè, raddoppiato; ad esempio,
    "Nat ""King"" Cole"

Nota:
- Siamo non che fare con i campi che possono contenere incorporato interruzioni di riga, come che richiederebbe un approccio fondamentalmente diverso, perché self-contained line-by l'elaborazione lineare non è più possibile.
- punta del cappello a Wiktor Stribiżew, che si avvicinò con la regex per abbinare con fermezza un campo virgolette doppie con un numero arbitrario di virgolette doppie incorporate, sfuggito come "": "([^"]*(?:""[^"]*)*)"

# Create sample CSV file with double-quoted fields that contain 
# just ',', just embedded double quotes ('""'), and both. 
@' 
bob,"1234 Main St, New York, NY","cool guy" 
nat,"Nat ""King"" Cole Lane","cool singer" 
nat2,"Nat ""King"" Cole Lane, NY","cool singer" 
'@ | Set-Content ./test.csv 

Get-Content ./test.csv | ForEach-Object { 
    # Match all double-quoted fields on the line, and replace those that 
    # contain neither commas nor embedded double quotes with just their content, 
    # i.e., with enclosing double quotes removed. 
    ([regex] '"([^"]*(?:""[^"]*)*)"').Replace($_, { param($match) 
    $fieldContent = $match.Groups[1] 
    if ($fieldContent -match '[,"]') { $match } else { $fieldContent } 
    }) 
} 

Questo produce:

bob,"1234 Main St, New York, NY",cool guy 
nat,"Nat ""King"" Cole Lane",cool singer 
nat2,"Nat ""King"" Cole Lane, NY",cool singer 

Aggiornamento del file di input:

Come in ans markg Con l'elaborazione riga per riga, non è possibile aggiornare direttamente il file di input con l'output nella stessa pipeline.
Per aggiornare il file iput successivamente, utilizzare un file di output temporaneo e quindi sostituire il file di input con esso (... rappresenta la Get-Content tubazione dall'alto, solo con $csvFile anziché ./test.csv):

$csvfile = 'c:\path\to\some.csv' 
$tmpFile = $env:TEMP\tmp.$PID.csv 
... | Set-Content $tmpFile 
if ($?) { Move-Item -Force $tmpFile $csvFile } 

notare che Set-Content usi la codifica dei caratteri ASCII estesa, a byte singolo, del sistema per impostazione predefinita (anche se help topicfalsely states ASCII).

Utilizzando il parametro -Encoding permette di specificare una codifica diversa, ma si noti che UTF-16, che è l'impostazione predefinita per Out-File/>, fa sì che il file CSV di non essere riconosciuto correttamente da Excel, per esempio.

Problemi correlati