Dire che ho un'espressione regolare come la seguente, ma l'ho caricata da un file in una variabile $ regex, e quindi non ho idea in fase di progettazione qual è il suo contenuto, ma in fase di esecuzione posso scoprire che comprende il "version1", "Version2", "versione 3" e "version4" gruppi denominati:PowerShell: sostituzione dell'espressione regolare dei gruppi denominati con le variabili
"Version (?<version1>\d),(?<version2>\d),(?<version3>\d),(?<version4>\d)"
... e non ho queste variabili:
$version1 = "3"
$version2 = "2"
$version3 = "1"
$version4 = "0"
.. .e trovo la seguente stringa in un file:
Version 7,7,0,0
... che viene memorizzato in una variabile $ input, in modo che ($ input -match $ regex) valuti $ true.
Come posso sostituire i gruppi denominati da $ regex nella stringa $ input con i valori di $ versione1, $ versione2, $ versione3, $ versione4 se non conosco l'ordine in cui compaiono in $ regex (I solo sapere che $ regex include questi gruppi con nome)?
Non riesco a trovare alcun riferimento che descriva la sintassi per la sostituzione di un gruppo denominato con il valore di una variabile utilizzando il nome del gruppo come indice per la corrispondenza: è addirittura supportato?
EDIT: Per chiarire - l'obiettivo è quello di sostituire su modelli stringhe di versione in qualsiasi tipo di file di testo in cui la stringa di versione in un dato file richiede la sostituzione di un numero variabile di campi di versione (potrebbe essere 2, 3, o tutti e 4 i campi). Ad esempio, il testo in un file potrebbe apparire come uno di questi (ma non è limitato a questi):
#define SOME_MACRO(4, 1, 0, 0)
Version "1.2.3.4"
SomeStruct vs = { 99,99,99,99 }
Gli utenti possono specificare un insieme di file e un'espressione regolare per abbinare la linea che contiene i campi, con la idea originale è che i singoli campi sarebbero catturati da gruppi con nome. L'utilità ha i valori dei campi della versione individuale che devono essere sostituiti nel file, ma deve conservare il formato originale della riga che conterrà le sostituzioni e sostituire solo i campi richiesti.
EDIT-2: credo di poter ottenere il risultato che ho bisogno con i calcoli di sottostringa in base alla posizione e l'entità di ciascuna delle partite, ma speravo operazione di sostituzione di PowerShell mi avrebbe risparmiare un po 'di lavoro.
EDIT-3: Così, come Ansgar correttamente e succintamente descrive di seguito, non v'è un modo (utilizzando solo la stringa di input originale, un'espressione regolare di cui si conosce solo i gruppi con nome, e la conseguente corrispondenze) per utilizzare l'operazione "-replace" (o altre operazioni regex) per eseguire sostituzioni delle acquisizioni dei gruppi denominati, lasciando intatto il resto della stringa originale. Per questo problema, se qualcuno è curioso, ho finito per usare la soluzione qui sotto. YMMV, altre soluzioni possibili. Mille grazie ad Ansgar per il suo feedback e le opzioni fornite.
Nel seguente blocco di codice:
- $ input è una linea di testo su cui sostituzione deve essere eseguita
- $ regex è un'espressione regolare (di tipo [stringa]) leggere un file che è stato verificato per contenere almeno uno dei gruppi denominati supportati
- $ regexToGroupName è una tabella hash che associa una stringa di espressioni regolari a una matrice di nomi di gruppi ordinati secondo l'ordine della matrice restituita da [regex] :: GetGroupNames(), che corrisponde all'ordine da sinistra a destra in cui appaiono nell'espressione
- $ groupNameToVersionNumber è una tabella hash che associa un nome di gruppo a un numero di versione.
I vincoli sui gruppi denominati all'interno di $ regex sono solo (penso) che l'espressione all'interno dei gruppi denominati non possa essere nidificata e che debba corrispondere almeno una volta all'interno della stringa di input.
# This will give us the index and extent of each substring
# that we will be replacing (the parts that we will not keep)
$matchResults = ([regex]$regex).match($input)
# This will hold substrings from $input that were not captured
# by any of the supported named groups, as well as the replacement
# version strings, properly ordered, but will omit substrings captured
# by the named groups
$lineParts = @()
$startingIndex = 0
foreach ($groupName in $regexToGroupName.$regex)
{
# Excise the substring leading up to the match for this group...
$lineParts = $lineParts + $input.Substring($startingIndex, $matchResults.groups[$groupName].Index - $startingIndex)
# Instead of the matched substring, we'll use the substitution
$lineParts = $lineParts + $groupNameToVersionNumber.$groupName
# Set the starting index of the next substring that we will keep...
$startingIndex = $matchResults.groups[$groupName].Index + $matchResults.groups[$groupName].Length
}
# Keep the end of the original string (if there's anything left)
$lineParts = $lineParts + $input.Substring($startingIndex, $input.Length - $startingIndex)
$newLine = ""
foreach ($part in $lineParts)
{
$newLine = $newLine + $part
}
$input= $newLine
Concordato che questo sarebbe bello, ma questo è per un programma di utilità in cui gli utenti specificano un'espressione regolare e un set di file. Non conosco la regex e non so come sia il contenuto del file, quindi non potrei usare la prima riga nella tua risposta senza riformattare il contenuto del file originale, il che sarebbe indesiderabile. Devo lasciare il contenuto del file dopo lo stesso aspetto, sostituendo solo le sottostringhe sulle linee corrispondenti con i singoli campi della versione. – Hoobajoob
Forse è possibile sostituire i gruppi con nome nell'espressione regolare con i numeri vecchi/nuovi effettivi e quindi eseguire una sostituzione di stringa. Ciò non funzionerà correttamente se l'espressione regolare contiene espressioni diverse dai gruppi con nome, comunque. –
Funziona quasi, anche se non so in anticipo come sono effettivamente definiti i gruppi denominati nella regex (ad esempio, potrebbero cercare \ d, \ d {2}, \ d +, un letterale, ecc.) . Posso introdurre alcuni vincoli sulla definizione di gruppo denominata e modificare la regex utilizzata nel ciclo for di cui sopra per ammettere uno o più caratteri dalla sintassi regex e alfanumerici (ad esempio, sostituire "\\ d" nella regex all'interno di i cicli for con "[a-zA-Z0-9 \\ + \. \ * \? \^\ $ \ {\} \ | \ [\]] +"). In ogni caso, questo approccio è preferibile alle operazioni di sottostringa. – Hoobajoob