首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何编写正则表达式来匹配多行模式?

如何编写正则表达式来匹配多行模式?
EN

Stack Overflow用户
提问于 2021-06-12 00:40:59
回答 3查看 59关注 0票数 1

我正在尝试使用PowerShell解析一个SFTP配置文件(sshd_config.txt)以获得所有现有的SFTP配置文件。下面的文本只是3个配置文件,但可能有数百个我需要解析。一旦我有了一个可以工作的正则表达式来将所有匹配输出到一个PowerShell对象,我应该可以很容易地解析各个配置文件。我就是想不出怎么写正则表达式。我确实尝试过使用其他示例,但我不能将每个示例分成单独的匹配。

我需要匹配开始的"^ match“和所有行,直到有一个空行。任何帮助都将不胜感激。

代码语言:javascript
复制
Match User thedomain\user1
    ChrootDirectory E:\sftp\heatism\user1
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand internal-sftp

Match User thedomain\user2
    ChrootDirectory E:\sftp\heatism\user2
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand internal-sftp

Match User thedomain\user3
    ChrootDirectory E:\sftp\heatism\user3
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand internal-sftp
EN

回答 3

Stack Overflow用户

发布于 2021-06-12 01:22:18

要跨多行进行匹配,请执行以下操作:

  • 您需要一个多行字符串作为输入,这是Get-Content-Raw开关提供的功能(默认情况下,Get-Content逐行输出输入文件的各行)。

代码语言:javascript
复制
- `Multiline` (`m`), in order to make `^` and `$` match the beginning and end of _individual lines_ inside a multi-line string; `\A` and `\Z` (or `\z`, to match only the very end of a string, even if it is a newline) can then be used to match the overall beginning and end of the multi-line string.
代码语言:javascript
复制
- `Singleline` (`s`) if you want `.` to also match _newline_ characters (`\n`).
代码语言:javascript
复制
- The simplest way to specify these options is inside `(?...)` at the start of the regex; in the case at hand: `(?ms)`

总而言之,使用Jan's helpful regex的修改版本和.NET System.Text.RegularExpressions.Regex.Matches()方法查找给定正则表达式的所有匹配项(请注意,PowerShell的-match operator只查找第一个匹配项):

代码语言:javascript
复制
foreach ($m in [regex]::Matches(
  (Get-Content -Raw sshd_config.txt), 
  '(?ms)^Match User .+?(?=^$|\Z)'
)) {
  # Split the block of line into the first and the remaining lines.  
  $first, $rest = $m.Value.Trim() -split '\r?\n'
  # Create an aux. (ordered) hashtable and fill it with the user name
  # extracted from the first line.
  $oht = [ordered] @{ UserName = (-split $first)[-1] }
  # Loop over the remaining lines, split them into name and value,
  # and add them to the hashtable.
  foreach ($line in $rest) {
    $name, $value = $line.Trim() -split ' ', 2
    $oht[$name] = $value
  }
  # Convert the hashtable to a custom object and output it.
  [pscustomobject] $oht
}

使用您的样例输入,您将看到以下输出,表示所创建的[pscustomobject]实例的默认格式:

代码语言:javascript
复制
UserName             : thedomain\user1
ChrootDirectory      : E:\sftp\heatism\user1
PermitTunnel         : no
AllowAgentForwarding : no
AllowTcpForwarding   : no
X11Forwarding        : no
ForceCommand         : internal-sftp

UserName             : thedomain\user2
ChrootDirectory      : E:\sftp\heatism\user2
PermitTunnel         : no
AllowAgentForwarding : no
AllowTcpForwarding   : no
X11Forwarding        : no
ForceCommand         : internal-sftp

UserName             : thedomain\user3
ChrootDirectory      : E:\sftp\heatism\user3
PermitTunnel         : no
AllowAgentForwarding : no
AllowTcpForwarding   : no
X11Forwarding        : no
ForceCommand         : internal-sftp
票数 3
EN

Stack Overflow用户

发布于 2021-06-12 00:45:32

你可以使用(多亏了的一些改进):

代码语言:javascript
复制
(?m)^Match[\s\S]+?(?=^$|\Z)

请参阅并注意multiline标志。

解释:

代码语言:javascript
复制
^Match    # match "Match" at the very beginning of a line
[\s\S]*?  # match anything else lazily
(?=^$|\Z) # make sure what follows is a blank line or the very end of the string
票数 2
EN

Stack Overflow用户

发布于 2021-06-12 04:31:13

另一种选择是以Match开头的模式,然后是该行的其余部分。然后继续使用负先行匹配所有非空行。

代码语言:javascript
复制
^Match .*(?:\r?\n(?!$).*)*

模式匹配:

  • ^Match
  • .*匹配line
  • (?:非捕获组的其余部分
    • \r?\n(?!$)匹配换行符,并断言该行不是empty
    • .*匹配line

的其余部分

  • )*关闭非捕获组,并根据需要重复

请参阅regex demo

如果您也不想匹配只包含空格的行:

代码语言:javascript
复制
^Match .*(?:\r?\n(?![\p{Zs}\t]*$).*)*

示例

代码语言:javascript
复制
$allText = Get-Content -Raw sshd_config.txt
$pattern = "(?m)^Match .*(?:\r?\n(?![\p{Zs}\t]*$).*)*"
Select-String $pattern -input $allText -AllMatches | Foreach-Object {$_.Matches} | Foreach-Object {
    $_.Value 
    "--------------------------"
}

输出

代码语言:javascript
复制
Match User thedomain\user1
    ChrootDirectory E:\sftp\heatism\user1
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand internal-sftp
--------------------------
Match User thedomain\user2
    ChrootDirectory E:\sftp\heatism\user2
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand internal-sftp
--------------------------
Match User thedomain\user3
    ChrootDirectory E:\sftp\heatism\user3
    PermitTunnel no
    AllowAgentForwarding no
    AllowTcpForwarding no
    X11Forwarding no
    ForceCommand internal-sftp
--------------------------
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67940654

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档