次のような正規表現があるとしますが、それをファイルから変数 $regex にロードしたため、設計時には内容がわかりませんが、実行時に「version1」が含まれていることを発見できます。 「version2」、「version3」、および「version4」の名前付きグループ:
"Version (?<version1>\d),(?<version2>\d),(?<version3>\d),(?<version4>\d)"
...そして私はこれらの変数を持っています:
$version1 = "3"
$version2 = "2"
$version3 = "1"
$version4 = "0"
...そして、ファイル内に次の文字列があります。
Version 7,7,0,0
...変数 $input に格納されるため、($input -match $regex) は $true と評価されます。
$regex に表示される順序がわからない場合、文字列 $input の $regex からの名前付きグループを $version1、$version2、$version3、$version4 の値に置き換えるにはどうすればよいですか ($正規表現にはこれらの名前付きグループが含まれます)?
グループ名を一致のインデックスとして使用して、名前付きグループを変数の値に置き換えるための構文を説明している参照が見つかりません。これはサポートされていますか?
編集: 明確にするために-目標は、特定のファイルのバージョン文字列が可変数のバージョンフィールド(2、3、または4つすべてのフィールド)の置換を必要とする、あらゆる種類のテキストファイルでテンプレート化されたバージョン文字列を置き換えることです)。たとえば、ファイル内のテキストは次のいずれかのようになります (ただし、これらに限定されません)。
#define SOME_MACRO(4, 1, 0, 0)
Version "1.2.3.4"
SomeStruct vs = { 99,99,99,99 }
ユーザーは、フィールドを含む行に一致するファイル セットと正規表現を指定できます。元のアイデアは、個々のフィールドが名前付きグループによってキャプチャされるというものでした。ユーティリティには、ファイル内で置換する必要がある個々のバージョン フィールド値がありますが、置換を含む行の元の形式を保持し、要求されたフィールドのみを置換する必要があります。
EDIT-2: 各一致の位置と範囲に基づいて部分文字列の計算を行うことで、必要な結果を得ることができると思いますが、Powershell の置換操作によって作業が節約されることを期待していました。
EDIT-3: したがって、Ansgar が以下で正しく簡潔に説明しているように、"- replace" 操作 (または他の正規表現操作) を使用して、元の文字列の残りの部分をそのまま残しながら、名前付きグループのキャプチャの置換を実行します。この問題について、誰かが興味を持っている場合は、以下の解決策を使用することになりました。YMMV、他の解決策が可能です。フィードバックとオプションを提供してくれた Ansgar に感謝します。
次のコード ブロックでは:
- $input は、置換が実行されるテキスト行です
- $regex は、サポートされている名前付きグループの少なくとも 1 つを含むことが確認されたファイルから読み取られた (タイプ [string] の) 正規表現です
- $regexToGroupName は、[regex]::GetGroupNames() によって返される配列の順序に従って並べ替えられたグループ名の配列に正規表現文字列をマップするハッシュ テーブルです。表現
- $groupNameToVersionNumber は、グループ名をバージョン番号にマップするハッシュ テーブルです。
$regex 内の名前付きグループに対する制約は、(私が思うに) 名前付きグループ内の式はネストできず、入力文字列内で最大 1 回一致する必要があるということだけです。
# 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