regexp 用于选择和验证逗号分隔字符串的字符串

regexp to select and validate a string of comma delimited strings

提问人:Tucker 提问时间:11/2/2023 最后编辑:Tucker 更新时间:11/14/2023 访问量:89

问:

专家们,我被困住了。我有一个字符串,上面有各种模式,用逗号分隔。我需要验证两件事:(1) 每个模式都与零个或多个逗号分隔的字符串匹配,以及 (2) 没有与模式不匹配的字符串。每个字符串元素都/将用逗号分隔(没有别的),逗号后面可能有尾随空格(我知道我可以在验证步骤之前用替换将其删除!

迄今采取的措施:

将字符串(按逗号)拆分为字符串元素数组 要匹配的字符串模式:

(a) single numbers e.g. 1,2,300,5,7,80 (up to 4 digits) etc.   
(b) ranges e.g. 1-5, 23-45,45-23 (up to 4 digits either side) etc.
(c) r1-r50, r45-r4 (up to 4 digits)
(d) 1-z, z-100
(e) string which contains one of two patterns 12-34:odd and 34-4:even

我想要的是通过对原始字符串的正则表达式比较将模式匹配字符串组直接拉入数组中,而不是将其拆分为数组(这当然有效!

那么,我需要什么正则表达式来过滤每个潜在的模式,并通过查看原始字符串来提取匹配的字符串元素?

这并不紧急,因为我有一个通过将它们拆分为元素的工作版本,但作为学习练习,我不清楚如何构造正则表达式并将其应用于带有逗号的字符串。

延伸问题:如何快速识别不遵循一种或多种模式的字符串元素。

谢谢

到目前为止,我所拥有的是:

(a) ^\d{0,5}*$
(b) ^\d{0,5}-\d{0,5}*$
(c) (?:z)
(d) (?:r)
(e) (?:odd|even)

所以代码提取:

$reg1 = '^\d{0,5}*$'    
$reg2 = '^\d{0,5}-\d{0,5}*$'
$reg3 = '(?:z)'           
$reg4 = '(?:r)'           
$reg5 = '(?:odd|even)'    

这应用于拆分为数组元素的字符串。

$phase1 = $rangearray | Select-String $reg1 -AllMatches | %{$_.Line} | sort # single numbers only
if($phase1.count -gt 0) { $Allpages[0].Single = $true; $Allpages[1].Single = @($phase1); }

$phase1 = $rangearray | Select-String $reg2 -AllMatches | %{$_.Line} # number ranges
if($phase1.count -gt 0) { $Allpages[0].Ranged = $true; $Allpages[1].Ranged = {$phase1}.Invoke(); }

$phase1 = $rangearray | Select-String $reg3 -AllMatches | %{$_.Line} # max range option z
if($phase1.count -gt 0) { $Allpages[0].Z = $true; $Allpages[1].Z = @($phase1); }

$phase1 = $rangearray | Select-String $reg5 -AllMatches | %{$_.Line} # odds and evens
if($phase1.count -gt 0) { $Allpages[0].OddEven = $true; $Allpages[1].OddEven = @($phase1); }

此函数传递一个字符串。该字符串的示例如下:

$range = '1-2,12-14,27-25,300-270,r10-r15,450-470:odd'
$range = '4, 2, 5, 14-12,16-18,20-19,r3-r1,285-290,r7-r4,388-z'
正则表达式 字符串 PowerShell

评论

2赞 Mathias R. Jessen 11/2/2023
先拆分,然后单独解析每个项目听起来像是一种更合理的方法 TBH
0赞 jdweng 11/2/2023
发布文件样本。可能有更简单的方法可以实现预期的结果。
0赞 Tucker 11/2/2023
已发布示例。另外,也许可以检查我的表情。我相信它们在单弦模式匹配上工作得很好。但我愿意改进......

答:

0赞 mklement0 11/3/2023 #1

我建议将 switch 语句与其 switch 一起使用,利用它迭代数组值输入的能力,以及它生成可以在数组中收集的多个输出的能力:-Regex

# Sample input string.
$range = ' 4, 2, 5, 14-12,16-18,20-19,r3-r1,285-290,r7-r4,388-z, 450-470:odd, WRONG'

[string[]] $validTokens = 
  switch -Regex (($range -split ',').Trim()) {
    '^\d{1,4}(?:-\d{1,4}(:(?:odd|even))?)?$' { $_; continue } # e.g. '4', '14-12', '450-470:odd'
    '^r\d{1,4}-r\d{1,4}$' { $_; continue } # e.g. 'r3-r1'
    '^z-\d{1,4}$' { $_; continue } # e.g. '388-z'
    '^\d{1,4}-z$' { $_; continue } # e.g. '1-z'
    default { Write-Warning "Doesn't match any expected pattern: '$_'" }
  }
  • ($range -split ',').Trim()拆分字符串,并从每个生成的元素中删除周围的空格。$range,

  • 然后,根据构成分支条件的正则表达式测试每个元素,如果它们与一个匹配,则通过 () 进行处理,然后处理移动到下一个元素 ()。$_continue

  • 仅当没有一个正则表达式匹配时,才会到达分支。default

若要处理多个范围,请在语句或调用中包含上述内容。foreachForEach-Object

0赞 Reilas 11/14/2023 #2

这是一个参考。

"...(a) 单个数字,例如1、2、300、5、7、80(最多4位数字)等......”

考虑一下,最后检查一下。

\d{1,4}

"...(b) 范围,例如 1-5、23-45、45-23(每边最多 4 位数字)等。
(e) 包含两种模式之一的字符串:12-34:奇数和 34-4:偶数......”

\d{1,4}-\d{1,4}(?::odd|even)?

"...(c) R1-R50、R45-R4(最多 4 位)......”

r\d{1,4}-r\d{1,4}

"...(d) 1-Z,Z-100......”

\d{1,4}-z|z-\d{1,4}

"...那么,我需要什么正则表达式来过滤每个潜在的模式,并通过查看原始字符串来提取匹配的字符串元素?..."

合并这些;下面是一个匹配模式

(?:r\d{1,4}-r\d{1,4}|\d{1,4}-\d{1,4}(?::odd|even)?|\d{1,4}-z|z-\d{1,4})|\d{1,4}

"...我需要验证两件事:(1) 每个模式都与零个或多个逗号分隔的字符串匹配,以及 (2) 没有与模式不匹配的字符串。..."

您需要先验证字符串

我认为您可以使用 和 语法来断言字符串的开头和结尾。
下面是一个示例。
^$

如果 p 是上述模式,则等同于^p(?:,\s*p)*$

^(?:(?:r\d{1,4}-r\d{1,4}|\d{1,4}-\d{1,4}(?::odd|even)?|\d{1,4}-z|z-\d{1,4})|\d{1,4})(?:,\s*(?:(?:r\d{1,4}-r\d{1,4}|\d{1,4}-\d{1,4}(?::odd|even)?|\d{1,4}-z|z-\d{1,4})|\d{1,4}))*$

从这里开始,使用初始模式来匹配每个值。

0赞 Prashant P 11/14/2023 #3

正则表达式说明:

((?:r\d{1,4}-r\d{1,4})|(?:\d{1,4}-\d{1,4}:(?:odd|even))|(?:z-\d{1,4})|(?:\d{1,4}-z)+|(?:\d{1,4}-\d{1,4})|(?:\d){1,4})(?:,|\s|$)

在应用正则表达式之前,不需要对字符串进行操作。您可以直接应用此正则表达式来获取所需的有效值。

请尝试根据需要添加/删除/修改最后一部分。(?:,|\s|$)

[1]: A numbered capture group. [(?:r\d{1,4}-r\d{1,4})|(?:\d{1,4}-\d{1,4}:(?:odd|even))|(?:z-\d{1,4})|(?:\d{1,4}-z)+|(?:\d{1,4}-\d{1,4})|(?:\d){1,4}]
      Select from 6 alternatives
          Match expression but don't capture it. [r\d{1,4}-r\d{1,4}]
              r\d{1,4}-r\d{1,4}
                  r
                  Any digit, between 1 and 4 repetitions
                  -r
                  Any digit, between 1 and 4 repetitions
          Match expression but don't capture it. [\d{1,4}-\d{1,4}:(?:odd|even)]
              \d{1,4}-\d{1,4}:(?:odd|even)
                  Any digit, between 1 and 4 repetitions
                  -
                  Any digit, between 1 and 4 repetitions
                  :
                  Match expression but don't capture it. [odd|even]
                      Select from 2 alternatives
                          odd
                              odd
                          even
                              even
          Match expression but don't capture it. [z-\d{1,4}]
              z-\d{1,4}
                  z-
                  Any digit, between 1 and 4 repetitions
          Match expression but don't capture it. [\d{1,4}-z], one or more repetitions
              \d{1,4}-z
                  Any digit, between 1 and 4 repetitions
                  -z
          Match expression but don't capture it. [\d{1,4}-\d{1,4}]
              \d{1,4}-\d{1,4}
                  Any digit, between 1 and 4 repetitions
                  -
                  Any digit, between 1 and 4 repetitions
          Match expression but don't capture it. [\d], between 1 and 4 repetitions
              Any digit
  Match expression but don't capture it. [,|\s|$]
      Select from 3 alternatives
          ,
          Whitespace
          End of line or string