Powershell 如何比较文件中的两个连续字符串
我有一个大文件,包括每个项目的“之前”和“之后”案例,如下所示:Powershell 如何比较文件中的两个连续字符串,powershell,Powershell,我有一个大文件,包括每个项目的“之前”和“之后”案例,如下所示: case1 (BEF) ACT (AFT) BLK case2 (BEF) ACT (AFT) ACT case3 (BEF) ACT (AFT) CLC ... 我需要选择所有在“第一个”字符串上有(BEF)ACT,在“第二个”字符串上有(AFT)BLK,并将结果放入文件中 我们的想法是创建一个如下的子句 IF (stringX.LineNumber consists of "(BEF) A
case1 (BEF) ACT
(AFT) BLK
case2 (BEF) ACT
(AFT) ACT
case3 (BEF) ACT
(AFT) CLC
...
我需要选择所有在“第一个”字符串上有(BEF)ACT
,在“第二个”字符串上有(AFT)BLK
,并将结果放入文件中
我们的想法是创建一个如下的子句
IF (stringX.LineNumber consists of "(BEF) ACT" AND stringX+1.LineNumber consists of (AFT) BLK)
{OutFile $stringX+$stringX+1}
抱歉,语法错误,我刚刚开始使用PS:)
创建一个新文件,结果如下:
带“(BEF)ACT”的字符串,后跟带“(AFT)BLK”的字符串
执行字符串文字子字符串匹配,这意味着您可以按原样传递搜索字符串,而无需转义它-SimpleMatch
- 但是,如果需要进一步限制搜索,例如确保搜索只发生在一行的末尾(
),则确实需要使用(隐含的)$
参数:-Pattern
'\(BEF\)ACT$'
- 另请注意,PowerShell默认情况下通常不区分大小写,这就是为什么使用开关
-CaseSensitive
- 但是,如果需要进一步限制搜索,例如确保搜索只发生在一行的末尾(
- 注意如何直接接受文件路径-无需前面的
调用Get Content
捕获每次匹配之前的-Context 0,1
行和之后的0
行,并将它们包含在1
输出的实例中Select String
- 在
脚本块中,ForEach对象
检索匹配后的行,并$\u0.Context.PostContext[0]
在其中执行文字子字符串搜索.Contains()
- 请注意,
是.NET.Contains()
类型的方法,与PowerShell不同,这些方法在默认情况下区分大小写,但您可以使用可选参数来更改李>系统.String
- 请注意,
- 如果在后续行中找到子字符串,则同时输出当前行和后续行
- 上面查找输入文件中的所有匹配对;如果您只想找到第一对,请将
附加到| Select Object-first 2
调用中Select String
$logFile = 'c:\temp\file.txt'
$outFile = 'c:\temp\file2.txt'
# read the content of the logfile as a single string
$content = Get-Content -Path $logFile -Raw
$regex = [regex] '(case\d+\s+\(BEF\)\s+ACT\s+\(AFT\)\s+BLK)'
$match = $regex.Match($content)
($output = while ($match.Success) {
$match.Value
$match = $match.NextMatch()
}) | Set-Content -Path $outFile -Force
使用时,结果为:
case1 (BEF) ACT
(AFT) BLK
case7 (BEF) ACT
(AFT) BLK
正则表达式详细信息:
- 完成您自己的基于
选择字符串的解决方案尝试
用途广泛,但速度较慢,尽管它适合处理太大而无法放入整个内存的文件,因为它逐行处理文件选择字符串
- 但是,PowerShell提供了一种更快的逐行处理替代方案:
-请参阅下面的解决方案
- 但是,PowerShell提供了一种更快的逐行处理替代方案:
- ,它首先将整个文件读入内存,根据文件大小的不同,总体性能可能最好,但由于严重依赖直接使用.NET功能,它的复杂性会增加
注意:仅当您希望将输出直接发送到管道到cmdlet(如
设置内容
)时,才需要封闭的$(…)
;在变量中捕获输出时不需要它:$pair=switch…
将分支条件解释为-Regex
- 分支的操作脚本块(
中的{…}
指的是手头的行$\
- 总体做法是:
一旦找到第一行,就会存储感兴趣的第一行,当找到第二行的模式并且设置了$firstLine
时(非空),就会输出该对$firstLine
处理程序重置default
,以确保只考虑包含感兴趣字符串的两个连续行$firstLine
-SimpleMatch'(BEF)ACT'
的字符串文字匹配切换回了使用-Pattern'\(BEF\)的基于正则表达式的匹配请注意,由于您的正则表达式实际上不使用任何正则表达式构造,字符串文字匹配在语法上更简单、更快。这是一个非常好的解决方案!从未想过使用开关(+1)谢谢,@Theo.Yes,switch-File
非常方便,但鲜为人知,大概是因为其他语言中的类似结构没有内置的文件处理能力,所以人们不会期望/记住它。
$logFile = 'c:\temp\file.txt'
$outFile = 'c:\temp\file2.txt'
# read the content of the logfile as a single string
$content = Get-Content -Path $logFile -Raw
$regex = [regex] '(case\d+\s+\(BEF\)\s+ACT\s+\(AFT\)\s+BLK)'
$match = $regex.Match($content)
($output = while ($match.Success) {
$match.Value
$match = $match.NextMatch()
}) | Set-Content -Path $outFile -Force
case1 (BEF) ACT
(AFT) BLK
case7 (BEF) ACT
(AFT) BLK
( Match the regular expression below and capture its match into backreference number 1
case Match the characters “case” literally
\d Match a single digit 0..9
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
\( Match the character “(” literally
BEF Match the characters “BEF” literally
\) Match the character “)” literally
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
ACT Match the characters “ACT” literally
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
\( Match the character “(” literally
AFT Match the characters “AFT” literally
\) Match the character “)” literally
\s Match a single character that is a “whitespace character” (spaces, tabs, line breaks, etc.)
+ Between one and unlimited times, as many times as possible, giving back as needed (greedy)
BLK Match the characters “BLK” literally
)
$(
$firstLine = ''
switch -CaseSensitive -Regex -File t.txt {
'\(BEF\) ACT' { $firstLine = $_; continue }
'\(AFT\) BLK' {
# Pair found, output it.
# If you don't want to look for further pairs,
# append `; break` inside the block.
if ($firstLine) { $firstLine, $_ }
# Look for further pairs.
$firstLine = ''; continue
}
default { $firstLine = '' }
}
) # | Set-Content ...