段落条件嵌套正则表达式(递归)

时间:2017-02-13 10:04:13

标签: java regex powershell if-statement paragraph

我需要一个与段落匹配的正则表达式:'&开始'(首先在示例文本中),直到'并结束'(最后一个来自示范文本)。问题是有时'& end a'没有明确指定,有时写成'& end'。当你有'& Start b'和'& end b'(有时也是'& end',因此混乱)时,问题就更大了。

此正则表达式的目标示例块是(抱歉将其作为代码块):

junk text

&Start a <

fulfilling text

fulfilling text

&Start b

&Start c

&end c

fulfilling text

&end

&end <

junk text

因此正则表达式应匹配所有段落的开头和结尾与包含&lt;的行。符号,虽然它不包含在原始文本中。 (即使用我们想要的&amp; Start X,并跳过'&amp; Start Y''和'end'(或'&amp; end Y')组直到'&amp; end'(或'&amp; end X''我们想要。

这不是一个简单的实现。我正在使用的表达式如下:

&start a([^&]*)(&end a|&end) 

哪个匹配良好隔离'并且启动''和'结束'段落,但当其他'&amp; start Y'行介于两者之间时,脚本会变得混乱。 我可能会使用一些If跳过不需要的块的if语句......这是一个更复杂的案例:

junk text

&Start a <

fulfilling text

fulfilling text

&Start b

&Start c

&end

fulfilling text

&end

&end <

junk text

不指定任何'&amp; end'。 注1:'&amp; start X'始终定义,但'&amp; end X'也可以'&amp; end',但始终对应于最接近的开始。 注2:由于堆栈溢出错误,我无法改变我的正则表达式的结构,而是适应这种特定情况。

对于奇怪的解释感到抱歉,但我希望有人可以找到任何可行的建议。

谢谢

编辑:

#@ -split "`n" | ForEach-Object { $_.trim() } |

$files = Get-ChildItem "$PSScriptRoot" # root path

for($i=0; $i -lt $files.Count; $i++){

    #iterate through files from the current folder.
    $data = Get-Content -Path $files[$i].FullName

    # parse DisabledFeatures.txt file as array of strings (1 string per line of the file)
    $feature = Get-Content DisabledFeatures.txt

    #iterate for each string entry in $feature array (read from txt file)
    for($counter=0; counter -lt $feature.Count; counter++){

        #retrieve array value to use it in the main algorythm
        $groupID = "$feature"

        $data | ForEach-Object -Begin { $ignore = $false; $levels = 0 } -Process {
            #Start ignoring text after we've found the trigger
            if($_ -match "^`#ifdef $groupID") { $ignore = $true }   
            #Track nested groups
            elseif($ignore) {
                if ($_ -match '^`#ifdef') { $levels++ }
                elseif ($_ -match '`#endif') {
                    if($levels -ge 1) { $levels-- }
                    #If no nesting, we've hit the end of our targeted group. Stop ignoring
                    else { $ignore = $false }
                }
            }
            #Write line
            else { $_ }
        }  
    }
}

1 个答案:

答案 0 :(得分:1)

纯正的正则表达式解决方案可能不是解决此问题的最佳解决方案。它可能已经完成,但它可能非常复杂且难以理解。我会使用一个简单的解析器。例如:

function Remove-TextGroup {
    param(
        [Parameter(Mandatory=$true)]
        [string[]]$Data,
        [Parameter(Mandatory=$true)]
        [string]$GroupID
    )

    $Data | ForEach-Object -Begin { $ignore = $false; $levels = 0 } -Process {
        #Start ignoring text after we've found the trigger
        if($_ -match "^&start $GroupID") { $ignore = $true }   
        #Track nested groups
        elseif($ignore) {
            if ($_ -match '^&start') { $levels++ }
            elseif ($_ -match '^&end') {
                if($levels -ge 1) { $levels-- }
                #If no nesting, we've hit the end of our targeted group. Stop ignoring
                else { $ignore = $false }
            }
        }
        #Write line
        else { $_ }

    }
}

用法:

$data = @"
junk text

&Start a <

fulfilling text

fulfilling text

&Start b

&Start c

&end

fulfilling text

&end

&end <

junk text
"@ -split "`n" | ForEach-Object { $_.trim() } |
#Remove empty lines
Where-Object { $_ }

Remove-TextGroup -Data $data -GroupID a    

#Or to read from file.. 
#$data = Get-Content -Path Myfile.txt
Remove-TextGroup -Data $data -GroupID a    

输出:

junk text
junk text

如果文件很大,我会优化上面的示例,使用streamreader来读取文件。