regex Powershell正则表达式问题,转义括号

p4tfgftt  于 2023-01-14  发布在  Shell
关注(0)|答案(3)|浏览(120)

我整天都在为这个问题绞尽脑汁,我已经接近了,但还没有完全达到目标。我有一个更大的脚本的一个小子集,只是正则表达式部分。下面是到目前为止的脚本:

$CCI_ID = @(
  "003417 AR-2.1"
  "003425 AR-2.9"
  "003392 AP-1.12"
  "009012 APP-1(21).1"
  )

  [regex]::matches($CCI_ID, '(\d{1,})|([a-zA-Z]{2}[-][\d][\(?\){0,1}[.][\d]{1,})') | 
      ForEach-Object {
        if($_.Groups[1].Value.length -gt 0){
          write-host $('CCI-' + $_.Groups[1].Value.trim())}
        else{$_.Groups[2].Value.trim()}
      }  

CCI-003417
AR-2.1
CCI-003425
AR-2.9
CCI-003392
AP-1.12
CCI-009012
PP-1(21
CCI-1

The output is correct for all but the last one. It should be:
      
      CCI-009012
      APP-1(21).1

Thanks for any advice.
f0brbegy

f0brbegy1#

不要分别描述和量化(可选的)左括号和右括号,而是将它们组合在一起,然后使 * 整个组 * 可选:

(?:\(\d+\))?

因此,整个模式最终看起来如下所示:

[regex]::Matches($CCI_ID, '(\d{1,})|([a-zA-Z]{2,3}[-][\d](?:\(\d+\))?[.][\d]{1,})')
yfwxisqw

yfwxisqw2#

在您的模式中,您使用了交替的|,但是查看示例数据,您可以在它后面匹配一个或多个空格。
如果存在模式匹配项,则组1的值已经包含一位或多位数字,因此不必检查Value.length
括号中包含可选数字的模式:

\b(\d+)\s+([a-zA-Z]{2,}-\d(?:\(\d+\))?\.\d+)\b

参见regex101 demo

$CCI_ID = @(
"003417 AR-2.1"
"003425 AR-2.9"
"003392 AP-1.12"
"009012 APP-1(21).1"
)

[regex]::matches($CCI_ID, '\b(\d+)\s+([a-zA-Z]{2,}-\d(?:\(\d+\))?\.\d+)\b') |
        ForEach-Object {
            write-host $( 'CCI-' + $_.Groups[1].Value.trim() )
            write-host $_.Groups[2].Value.trim()
        }

产出

CCI-003417
AR-2.1
CCI-003425
AR-2.9
CCI-003392
AP-1.12
CCI-009012
APP-1(21).1
jgwigjjp

jgwigjjp3#

正如您在这里所经历的,Regex表达式可能变得非常复杂和不可读。
因此,从两个不同的Angular 来看待你的问题通常是一个好主意:

  • 尝试匹配所需的部件**,或
  • 尝试匹配您 * 不 * 想要部件

在您的情况下,匹配您不想要的部分可能更容易:分隔符,* 空格 *,并在此基础上拆分字符串,这显然是想要实现的:

$CCI_ID | Foreach-Object {
    $Split = $_ -Split '\s+', 2
    'CCI-' + $Split[0]
    $Split[1]
}

$_ -Split '\s+', 2,基于一个或多个空格拆分相关字符串(其中您也可以考虑文字空格:-Split ' ')。, 2将防止字符串拆分为两个以上的部分。这意味着第二部分将不会被进一步拆分,即使它包含空格。

相关问题