說我有一個像下面這樣的正則表達式,但是我把它從一個文件加載到一個變量$ regex中,所以在設計時不知道它的內容是什麼,但是在運行時我發現,它包括 「VERSION1」, 「版本2」, 「版本3」 和 「版本4」 命名組:Powershell:用變量替換名爲組的變量
"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替換名爲groups的$ version1,$ version2,$ version3,$ version4的值只知道$ regex包含這些命名組)?
我找不到任何引用,描述用組名作爲匹配索引來替換命名組的語法,這是甚至支持嗎?
編輯: 爲了澄清 - 我們的目標是在任何一種文本文件,其中在給定的文件版本字符串需要更換版本領域的可變數量的替換模板版本字符串(可能是2,3,或全部4個領域)。例如,在一個文件中的文本可能看起來像任何這些(但不限於這些):
#define SOME_MACRO(4, 1, 0, 0)
Version "1.2.3.4"
SomeStruct vs = { 99,99,99,99 }
用戶可以指定一個文件組和正則表達式匹配包含的字段行,與原來的想法是個別領域將被命名組捕獲。該實用程序具有應在文件中替換的各個版本字段值,但必須保留將包含替換的行的原始格式,並僅替換請求的字段。
EDIT 2: 我想我能得到的結果我需要根據每個比賽的位置和程度串計算,但希望PowerShell的替換操作是要救我一些工作。
編輯-3: 所以,下面安斯加爾正確而簡潔的描述,沒有一種方法(僅使用原始輸入字符串,正則表達式關於你只知道命名組,並將所得匹配)使用「替換」操作(或其他正則表達式操作)來執行指定組捕獲的替換,同時保留原始字符串的其餘部分不變。對於這個問題,如果有人好奇,我最終會使用下面的解決方案。 YMMV,其他可能的解決方案。非常感謝Ansgar提供的反饋和選項。
在下面的代碼塊:
- $輸入是文本的線在其上取代是將要執行
- $正則表達式是從文件中讀取一個正則表達式(類型的[字符串])已被驗證包含至少一個受支持的命名組
- $ regexToGroupName是一個哈希表,它將一個正則表達式字符串映射到按照由[regex]返回的數組順序排列的組名數組:: GetGroupNames (),它與它們在表達式 中出現的從左到右的順序相匹配
- $ groupNameToVersionNumber是一個散列表,它將組名映射到版本號。
對$ regex中指定組的限制只是(我認爲)指定組中的表達式不能嵌套,並且在輸入字符串中最多一次匹配。
# 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
一致認爲,這將是很好的,但這是爲用戶指定正則表達式和文件集的實用程序。我不知道正則表達式,我不知道文件內容是什麼樣的,所以我不能在你的答案中使用第一行,而不用重新格式化原始文件內容,這是不可取的。之後我必須保持文件內容不變,只用相應的版本字段替換匹配行上的子字符串。 – Hoobajoob
也許您可以用正確的舊/新數字替換正則表達式中的命名組,然後執行字符串替換。但是,如果正則表達式包含除命名組以外的表達式,那麼這將無法正常工作。 –
這幾乎可行,但我事先並不知道如何定義正則表達式中的命名組(例如,它們可能正在查找\ d,\ d {2},\ d +,一個字面等) 。我可以對指定的組定義引入一些約束,並更改上面for循環中使用的正則表達式,以允許從正則表達式語法中接受一個或多個字符以及字母數字(例如,在正則表達式中替換正則表達式中的「\\ d」 「[a-zA-Z0-9 \\ + \。\ * \?\^\ $ \ \ \ \ \ \ \ \ [\]] +」)的for循環。無論如何,這種方法比子串操作更可取。 – Hoobajoob