我正在尝试匹配regex并在文件中替换匹配。我的正则表达式如下(与之匹配很好):
$regex1 = [regex] "index.php\?title\=[a-zA-Z0-9_]*"我试图在以下文件中运行替换的源文件的经过编辑的摘录:
<content:encoded>
<![CDATA[<a href="http://[redacted]/index.php?title=User_Manual">
<a href="http://[redacted]/index.php?title=User_Manual">The software</a>, running on the
<a href="http://[redacted]/index.php?title=Mobile_Device">POS Device</a>, enables
<a href="http://[redacted]/index.php?title=Logging_In">log in</a>,
<a href="http://[redacted]/index.php?title=Selecting_Journey">select a journey</a>而Powershell替换:
.Replace("index.php?title=","").Replace("_","-").ToLower())我提取了所有匹配项,将$allmatches数组强制转换为一个新数组(因此它是可写的),然后更新新数组中的值。我想不出如何将它写回文件,而且似乎找不到任何文章或文档来帮助解决这个问题。我的代码到目前为止:
$regex1 = [regex] "index.php\?title\=[a-zA-Z0-9_]*"
$contentOf=Get-Content $contentfile
$allmatches=$regex1.Matches($contentOf)
$totalcount=$allmatches.Count
$newArray = $allmatches | select *
for($i=0;$i -le $totalCount;$i++) {
$newvalue=(($allmatches[$i].Value).Replace("index.php?title=","").Replace("_","-").ToLower())
$newArray[$i].Value = $newvalue
}此时,我有一个包含所有regex匹配和替换的数组$newArray,但不知道如何将其写回我的文件/变量(如$newarray[0] )。
Groups : {0}
Success : True
Name : 0
Captures : {0}
Index : 4931
Length : 40
Value : user-manual当然,我这样做完全是错误的。就我为什么选择Powershell来做这件事而言,仅仅是因为这是我花了大部分时间编写这些days...of课程的地方,我确信它在shell中是可以实现的(我需要更长的时间才能达到这个目的)。
发布于 2019-11-19 17:16:28
实际上,这是在regex和正则表达式中的.Net替换中使用捕获组的好地方。修改后的正则表达式是:
$regex = [regex] 'index\.php\?title\=(\p{L}*)_(\p{L}*)'\p{L}匹配任何字母(由Unicode定义,而不仅仅是A)。(\p{L}*)是一个只包含字母的编号捕获组。$1和$2来引用每个捕获组:'$1-$2'。注意在替换字符串上使用单引号'',以防止PowerShell变量在$1和$2上展开。简单替代
如果我们只关心捕获组,我们可以只使用以下代码:
$testContent = @'
<content:encoded>
<![CDATA[<a href="http://[redacted]/index.php?title=User_Manual">
<a href="http://[redacted]/index.php?title=User_Manual">The software</a>, running on the
<a href="http://[redacted]/index.php?title=Mobile_Device">POS Device</a>, enables
<a href="http://[redacted]/index.php?title=Logging_In">log in</a>,
<a href="http://[redacted]/index.php?title=Selecting_Journey">select a journey</a>
'@
$regex = [regex] 'index\.php\?title\=(\p{L}*)_(\p{L}*)'
$modifiedContent = [regex]::Replace($testContent, $regex, '$1-$2')其结果是:
<content:encoded>
<![CDATA[<a href="http://[redacted]/index.php?title=User_Manual">
<a href="http://[redacted]/index.php?title=User_Manual">The software</a>, running on the
<a href="http://[redacted]/index.php?title=Mobile_Device">POS Device</a>, enables
<a href="http://[redacted]/index.php?title=Logging_In">log in</a>,
<a href="http://[redacted]/index.php?title=Selecting_Journey">select a journey</a>这种方法的问题是,不允许我们将组更改为小写。正则表达式实际上并没有处理这个需求的方法。幸运的是,.Net有一个扩展,允许我们轻松地处理更复杂的情况。
使用MatchEvaluator委托
MatchEvaluator是一个对象,可以与regex替换方法的重载一起使用,用于正常替换不足的情况。在PowerShell中,它们可以是一个简单的具有[Match]参数的scriptblock:
$testContent = @'
<content:encoded><![CDATA[<a href="http://[redacted]/index.php?title=User_Manual">
<content:encoded>
<![CDATA[<a href="http://[redacted]/index.php?title=User_Manual">
<a href="http://[redacted]/index.php?title=User_Manual">The software</a>, running on the
<a href="http://[redacted]/index.php?title=Mobile_Device">POS Device</a>, enables
<a href="http://[redacted]/index.php?title=Logging_In">log in</a>,
<a href="http://[redacted]/index.php?title=Selecting_Journey">select a journey</a>
'@
$regex = [regex] 'index\.php\?title\=(\p{L}*)_(\p{L}*)'
$MatchEvaluator = {
param($match)
$group1 = $match.Groups[1].Value.toLower()
$group2 = $match.Groups[2].Value.toLower()
return "$group1-$group2"
}
[regex]::Replace($testContent, $regex, $MatchEvaluator)它提供了所期望的结果:
<content:encoded>
<![CDATA[<a href="http://[redacted]/index.php?title=User_Manual">
<a href="http://[redacted]/index.php?title=User_Manual">The software</a>, running on the
<a href="http://[redacted]/index.php?title=Mobile_Device">POS Device</a>, enables
<a href="http://[redacted]/index.php?title=Logging_In">log in</a>,
<a href="http://[redacted]/index.php?title=Selecting_Journey">select a journey</a>替换文件的内容
最后的代码如下所示:
# Load the file as a single string
$content = Get-Content $contentfile -Raw
# Regex to replace, with capturing groups
$regex = [regex] 'index\.php\?title\=(\p{L}*)_(\p{L}*)'
# Delegate to transfrom capture groups into lowercase
$MatchEvaluator = {
param($match)
$group1 = $match.Groups[1].Value.toLower()
$group2 = $match.Groups[2].Value.toLower()
return "$group1-$group2"
}
# Replace all matches of the regular expression with delegate
$modifiedContent = [regex]::Replace($Content, $regex, $MatchEvaluator)
# Overwrite existing file
$modifiedContent | Out-File $contentfile发布于 2019-11-19 14:17:00
我提取了所有匹配项,将
$allmatches数组强制转换为一个新数组(因此它是可写的),然后更新新数组中的值。
你不需要这样做,问题的解决要简单得多。您所需要做的就是对原始文件使用Get-Content,并对每一行进行迭代。您还可以使用-replace运算符而不是[Regex]类来处理替换:
Get-Content $contentFile | Foreach-Object {
$_ = ( $_ -replace 'index.php\?title=' ) -replace '_', '-'
} | Set-Content $contentFile您可以直接将Get-Content的结果输送到Foreach-Object。对于每一行,我们希望用一个空字符串替换index.php\?title= (您可以省略-replace的第二个参数作为这个参数的缩写)。然后,我们还将该行的_替换为-。它对文件中的每一行执行此操作。然后将更改的内容以管道方式发送到Set-Content,然后将其写回原始文件。
作为旁白,当您使用-match运算符(我们在上面没有使用它)匹配正则表达式时,您可以检查自动$Matches变量,以了解表达式如何与字符串匹配,该字符串类似于[Regex]::Matches返回的内容。
https://stackoverflow.com/questions/58935570
复制相似问题