我正在尝试从文本文件中取消日期。这是内容:
存储管理器 命令行管理界面 - 版本7,版本1,级别1.4 (c)公司和其他(1990),2015年的版权。保留所有权利。
与服务器TSERVER建立的会话:Windows 服务器版本7,版本1,级别5.200 服务器日期/时间:11/22/2016 15:30:00最后访问:11/22/2016 15:25:00
ANS8000I服务器命令。
我需要在服务器日期/时间之后提取日期/时间。我写了这个正则表达式:
/([0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})/
这在regex101中完美运行。请参阅https://regex101.com/r/MB7yB4/1上的示例 然而,在Powershell中,它的反应不同。
$var -match "([0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})"
给出
服务器日期/时间:11/22/2016 16:30:00最后访问:2016年11月22日 15点37分十九秒
和
$var -match "([0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})"
什么都没有。
我不确定为什么比赛不一样。
感谢您的帮助!
答案 0 :(得分:2)
-match
运算符返回一个布尔值,显示是否找到匹配项。此外,它使用匹配数据(整个匹配和捕获组值)设置$matches
变量。你只需要访问整场比赛:
if($var -match '[0-9]{1,2}/[0-9]{1,2}/[0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2}') { $matches[0] }
请参阅Using -match
and the $matches
variable in PowerShell。
请注意,在Powershell regexp中不需要转义/
synmbol,因为这个字符并不特殊,并且在定义时不使用正则表达式分隔符(JS,PHP regexp中的那些外部/.../
) Powershell中的正则表达式。
答案 1 :(得分:1)
这是因为你匹配了几行,它正在拉出匹配的行,从行中取出单个匹配使用以下内容:
foreach ($line in $var) { if ($line -match "([0-9]{1,2}\/[0-9]{1,2}\/[0-9]{4} [0-9]{1,2}:[0-9]{1,2}:[0-9]{1,2})") {write-output $matches[0]}}
答案 2 :(得分:1)
如果您正在处理冗长的RE,那么使用命名捕获组是有意义的。将RE拆分为多个时,名称保持不变。当RE可能跨越多行时,您应该使用(?smi)
并且为了能够将crlf与.
匹配,您必须使用-raw选项获取内容。我使用\ d而不是[0-9]来保存3个字符。
$var = Get-Content File.txt -Raw
if ($var -match "(?smi)Server date/time: (?<ServerDT>\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{1,2}:\d{1,2}).*access: (?<LastAc>\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{1,2}:\d{1,2})") {
"ServerDT : "+$matches.ServerDT
"LastAccess: "+$matches.LastAc
}
输出
ServerDT : 11/22/2016 15:30:00
LastAccess: 11/22/2016 15:25:00
答案 3 :(得分:1)
补充Wiktor Stribiżew's helpful answer,其中包含许多有用的指针和有效的解决方案,但没有正确解释 array 输入的-match
运算符的行为:
-match
运算符的行为会发生变化:返回匹配数组元素而不是布尔值。实际上,-match
然后执行数组过滤。
$var
将文件内容读入Get-Content
,这会将行返回为字符串 array 而不是单个字符串。在PSv3 +中,添加开关-Raw
将整个文件作为单个字符串读取。$Matches
哈希表的条目,以便访问有关最近使用-match
捕获的内容的信息 :$Matches[0]
包含正则表达式整体捕获的内容,$Matches[1]
第一个(未命名)捕获组捕获的内容(第二个$Matches[2]
,...)和{{1} } 命名捕获组,如LotPing's helpful answer中所示。 ($Matches['<name>']
只是$Matches.0
的替代语法,例如)。$Matches[0]
)来定义正则表达式,以便PowerShell自己的字符串插值应用于双引号字符串('...'
)不会妨碍你。使用正则表达式提取子字符串时,使用"..."
通常可以提供更简洁的解决方案:
-replace
需要额外的$var -join "`n" -replace '(?s).*?(\d{1,2}/\d{1,2}/\d{4} \d{1,2}:\d{1,2}:\d{1,2}).*', '$1'
步骤才能将-join "`n"
中的行数组重新组合为单个字符串,以作为输入传递给$var
。
下面的说明显示了如何使用-replace
将整个文件作为单个字符串读取。
<强>解释强>
Get-Content -Raw
答案 4 :(得分:0)
在这种情况下,我仍然喜欢直接使用.NET regex类匹配方法 - 它更快,更精确,更详细。如果您确定第一个日期是您搜索的结果,则可以使用:
[regex]::Matches($var,'\d{1,2}/\d{1,2}/\d{4}\s\d{1,2}:\d{1,2}:\d{1,2}')[0].value
我个人会将“服务器日期/时间:”放入正则表达式中,然后将其从结果中删除(如果有必要,则将清除结果解析为DateTime对象)。
([regex]::Matches($a,'Server\sdate/time:\s\d{1,2}/\d{1,2}/\d{4}\s\d{1,2}:\d{1,2}:\d{1,2}').value) -replace "Server date/time: ",''
PS。一个快速建议,即使对于测试,也要避免将var用作变量名。真是个坏习惯。