Quindi, quello che stai dicendo è che vuoi sostituire una qualsiasi di 600 stringhe in ciascuna delle 150.000 linee e vuoi eseguire un'operazione di sostituzione per riga?
Sì, c'è un modo per farlo, ma non in PowerShell, almeno non riesco a pensarne uno. Può essere fatto in Perl.
Il Metodo:
- costruire un hash in cui le chiavi sono i quarantina ed i valori sono le somethingelses.
- Unire le chiavi dell'hash con il | Simbolo e usarlo come gruppo di corrispondenza nella regex.
- In sostituzione, interpolare un'espressione che recupera un valore dalla hash utilizzando la variabile partita per il gruppo Capture
Il problema:
Frustratingly, PowerShell non espone la partita le variabili al di fuori della regex sostituiscono la chiamata. Non funziona con l'operatore -replace e non funziona con [regex] :: replace.
In Perl, si può fare questo, per esempio:
$string =~ s/(1|2|3)/@{[$1 + 5]}/g;
Questo aggiungerà 5 alle cifre 1, 2, e 3 per tutta la stringa, quindi se la stringa è "1.224.526,123 mila [2] [ 6] ", diventa" 6774576678 [7] [6] ".
Tuttavia, in PowerShell, entrambi questi falliscono:
$string -replace '(1|2|3)',"$($1 + 5)"
[regex]::replace($string,'(1|2|3)',"$($1 + 5)")
In entrambi i casi, $ 1 vale NULL, e l'espressione restituisce vecchi 5. Le variabili partita di pianura in sostituzioni sono significativi solo in la stringa risultante, vale a dire una stringa con quotatura singola o qualunque sia la stringa a virgolette valutata. Sono fondamentalmente solo backreferenze che assomigliano a variabili di corrispondenza. Certo, puoi citare il $ prima del numero in una stringa con doppia citazione, quindi valuterà il corrispondente gruppo di corrispondenza, ma ciò vanifica lo scopo - non può partecipare a un'espressione.
La soluzione:
[Questa risposta è stata modificata rispetto all'originale. È stato formattato per adattarsi alle stringhe di corrispondenza con i metacaratteri regex. . E il vostro schermo piatto, ovviamente]
Se si utilizza un'altra lingua è accettabile per voi, il seguente script Perl funziona come un fascino:
$filePath = $ARGV[0]; # Or hard-code it or whatever
open INPUT, "< $filePath";
open OUTPUT, '> C:\log.txt';
%replacements = (
'something0' => 'somethingelse0',
'something1' => 'somethingelse1',
'something2' => 'somethingelse2',
'something3' => 'somethingelse3',
'something4' => 'somethingelse4',
'something5' => 'somethingelse5',
'X:\Group_14\DACU' => '\\DACU$',
'.*[^xyz]' => 'oO{xyz}',
'moresomethings' => 'moresomethingelses'
);
foreach (keys %replacements) {
push @strings, qr/\Q$_\E/;
$replacements{$_} =~ s/\\/\\\\/g;
}
$pattern = join '|', @strings;
while (<INPUT>) {
s/($pattern)/$replacements{$1}/g;
print OUTPUT;
}
close INPUT;
close OUTPUT;
Cerca le chiavi del cancelletto (a sinistra il =>) e li sostituisce con i valori corrispondenti. Ecco cosa sta succedendo:
- Il foreach ciclo passa attraverso tutti gli elementi del hash e di creare un array chiamato @strings che contiene le chiavi dei% sostituzioni hash, con metacaratteri citato utilizzando \ Q e \ E e il risultato di quello indicato per l'uso come modello regex (qr = quote regex). Nello stesso passaggio, sfugge a tutti i backslash presenti nelle stringhe sostitutive raddoppiandoli.
- Successivamente, gli elementi dell'array vengono uniti con | per formare il modello di ricerca. Potresti includere le parentesi di raggruppamento nel modello $ se lo desideri, ma penso che in questo modo sia più chiaro cosa sta succedendo.
- Il ciclo mentre legge ogni riga dal file di input, sostituisce qualsiasi stringa nel modello di ricerca con le stringhe di sostituzione corrispondenti nell'hash e scrive la riga nel file di output.
BTW, potreste aver notato diverse altre modifiche dalla sceneggiatura originale. Il mio Perl ha raccolto un po 'di polvere durante il mio recente calcio PowerShell, e in un secondo sguardo ho notato diverse cose che potevano essere fatte meglio.
while (<INPUT>)
legge il file una riga alla volta. Molto più ragionevole della lettura di tutte le 150.000 linee in un array, specialmente quando il tuo obiettivo è l'efficienza.
- I semplificato
@{[$replacements{$1}]}
a $replacements{$1}
. Perl non ha un modo incorporato di interpolazione di espressioni come PowerShell $(), quindi @ {[]} viene utilizzato come soluzione alternativa: crea un array letterale di un elemento contenente l'espressione. Ma mi sono reso conto che non è necessario se l'espressione è solo una singola variabile scalare (l'ho avuta lì come un residuo del mio test iniziale, dove stavo applicando i calcoli alla variabile di partita $ 1).
- Le istruzioni close non sono strettamente necessarie, ma è buona norma chiudere i filehandle in modo esplicito.
- Ho modificato per abbreviazione in foreach, per renderlo più chiaro e più familiare ai programmatori PowerShell.
Grazie per la risposta, sono nuovo di Perl e ho cercato di implementare la soluzione, ma sono venuto su w con un problema con la sintassi. Voglio sostituire una stringa che assomigli a '' X: \ Group_14 \ DACU "' con la seguente stringa '" \\ DACU $ "'. Ho provato qualcosa del tipo ''X: \ Group_14 \ DACU' => '[\\ DACU $]'' Ma sembra che non funzioni, la mia sintassi è corretta? – Richard
Ah, ho trascurato la gestione di personaggi speciali, come sciatta. Il problema è che il backslash è il carattere di escape in Perl (equivalente a un backtick in Powershell). Anche se hai citato una sola stringa, i problemi si verificano quando è interpolato in un'espressione regolare, in cui la barra indica varie sequenze di escape con significati speciali. Ad esempio, ** \ D ** indica qualcosa di diverso da una cifra e ** \ G ** indica l'offset dell'ultima corrispondenza globale sulla stringa (non preoccuparti di ciò ...). Modificheremo la risposta per citare le chiavi dell'hash da usare in un'espressione regolare. –