我有一个名称分隔符,我想用它来提取整行。
[string]$testString = $null
# broken text string of text & newlines which simulates $testString = Get-Content -Raw
$testString = "initial text
preliminary text
unfinished line bfore the line I want
001 BOURKE, Bridget Mary ....... ........... 13 Mahina Road, Mahina Bay.Producrs/As 002 BOURKE. David Gerard ...
line after the line I want
extra text
extra extra text"
# test1
# simulate text string before(?<content>.*)text string after - this returns "initial text" only (no newline or anything after)
# $testString -match "(?<BOURKE>.*)"
# test2
# this returns all text, including the newlines, so that $testString outputs exactly as it is defined
$testString -match "(?s)(?<BOURKE>.*)"
#test3
# I want just the line with BOURKE
$result = $matches['BOURKE']
$result
#Test1找到匹配项,但只打印到换行符#Test2查找匹配项并包含所有换行符。我想知道强制输出开始001 BOURKE ...
的正则表达式模式是什么
如有任何建议,我们将不胜感激。
注意:
-
我假设您正在查找整行,
BOURKE
作为子字符串出现在该行上。 -
在您自己的尝试中,
(?<BOURKE>...)
只是给正则表达式捕获组一个自己选择的名称(BOURKE
),这与捕获组的子表达式(...
)实际匹配的内容无关。 -
对于手头的用例,根本不需要严格使用(命名的)捕获组,因此下面的解决方案可以不使用捕获组,当使用
-match
运算符时,这意味着在自动$Matches
变量的索引[0]
中报告成功匹配的结果,如下所示。
如果多行输入字符串只包含Unix格式的LF换行符(n
),请使用以下命令:
if ($multiLineStr -match '.*BOURKE.*') { $Matches[0] }
注:
- 要敏感地匹配大小写-,请使用
-cmatch
而不是-match
- 如果您知道子字符串前面/后面至少有一个字符。,使用
.+
而不是.*
- 如果您想逐字逐句地搜索子字符串,并且它恰好或可能包含正则表达式元字符(例如
.
),请对其应用[regex]::Escape()
;例如[regex]::Escape('file.txt')
产生file.txt
(-转义元字符)
- 如有必要,添加额外的消歧约束,例如要求子串仅在单词边界处开始或结束(
b
)
如果存在Windows格式CLRF换行符(rn
),请使用:
if ($multiLineStr -match '.*BOURKE[^rn]*') { $Matches[0] }
有关正则表达式及其实验能力的解释,请参阅此regex101.com页面(适用于.*BOURKE.*
)和此页面(用于.*BOURKE[^rn]*
)
简而言之:
- 默认情况下,
.
匹配除n
之外的任何字符,这完全不需要特定于行的锚(^
和$
),但对于CRLF换行符,需要排除r
,以免将其作为匹配的一部分捕获[1]
两个旁白:
PowerShell的
-match
运算符只查找一个匹配项;如果需要查找所有匹配,则当前需要直接使用底层[regex]
API;例如,[regex]::Matches($multiLineStr, '.*BOURKE[^rn]*').Value, 'IgnoreCase'
GitHub问题#7867建议以-matchall
运算符的形式将此功能直接引入PowerShell。如果您想锚定子串以查找,即如果您想规定它发生在一行的开头或结尾,则需要切换到多行模式(
(?m)
),这使得^
和$
在每行上匹配;例如,仅当BOURKE
出现在一行的最开始时匹配:if ($multiLineStr -match '(?m)^BOURKE[^rn]*') { $Matches[0] }
如果逐行处理是一个选项:
逐行处理的优点是不必担心换行格式的差异(假设处理拆分为行的实用程序可以处理这两种换行格式,PowerShell通常也是如此)。
如果您正在从文件中读取输入文本,
Select-String
cmdlet(其目的是查找给定正则表达式或文字子字符串(-SimpleMatch
)与其匹配的整行)还提供流式处理,即逐行读取,而无需将整个文件
(Select-String -LiteralPath file.txt -Pattern BOURKE).Line
为区分大小写的匹配添加-CaseSensitive
以下示例模拟了上面的内容(-split 'r?n'
将多行输入字符串拆分为单独的行,识别换行格式):
(
@'
initial text
preliminary text
unfinished line bfore the line I want
001 BOURKE, Bridget Mary ....... ........... 13 Mahina Road, Mahina Bay.Producrs/As 002 BOURKE. David Gerard ...
line after the line I want
extra text
extra extra text
'@ -split 'r?n' |
Select-String -Pattern BOURKE
).Line
输出:
001 BOURKE, Bridget Mary ....... ........... 13 Mahina Road, Mahina Bay.Producrs/As 002 BOURKE. David Gerard ...
[1]严格地说,[^rn]*
也会在隔离的r
字符处停止匹配(即,即使不直接跟在n
后面)。如果排除这种情况很重要(这似乎不太可能),请使用Mathias R.Jessen在对问题的评论中建议的正则表达式(的简化版本):.*BOURKE.*?(?=r?n)
我发现最好让一场比赛消耗掉不需要的东西;即CCD_ 45。这可以用集合中具有^
的集合命名法来完成,例如[^rn]+
,其表示消耗高达r
或n
。因此,所有而不是的内容都是rn
。
要做到这一点,请使用
$testString -match "(?<Bourke>ddds[^rn]+)"
当知道有可匹配的txt时,也应该尽量避免*
。。。CCD_ 52是消耗一切的贪婪类型。一个或多个+
的使用大大限制了匹配,因为解析器不必尝试模式(*
的零为零或更多),回溯作为其调用,这显然是不可信的。