使用正则表达式拆分字符串似乎不如预期的那样工作。

huangapple go评论67阅读模式
英文:

Spliting Strings by regex seems not to work as expected

问题

在PowerShell中有一个函数:

function WriteToLog {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [AllowEmptyCollection()]
        [AllowEmptyString()]
        [string[]]$Message
    )
    BEGIN {}
    PROCESS {
        if ($Null -ne $Message) {
            $dt = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
            foreach ($item in $Message) {
                if ($item.length -gt 0) {
                    $it = $item -split '(.{1,70})' | Where-Object {$_}
                    $dt + ": " + $it[0] | Write-Host
                    $dt = $dt -replace '(.)',' '
                    $i = 1
                    while ($it[$i]) {
                        $dt + "  " + $it[$i] | Write-Host
                        $i++
                    }
                }
            }
        }
    }
    END {}
}

现在使用字符串调用它:

"----" | WriteToLog

输出:

2023-05-25 00:28:05: -
                     -
                     -
                     -
                     -

我希望的是:

2023-05-25 00:28:05: -----

而不是将字符串拆分成字符。
如果字符串长度超过70个字符,它会按预期工作:

"--------------------------------------------------------------------------" | WriteToLog

输出:

2023-05-25 00:32:37: ----------------------------------------------------------------------
                     ----

有任何想法为什么会这样?

英文:

Having a function in PowerShell:

function WriteToLog {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [AllowEmptyCollection()]
        [AllowEmptyString()]
        [string[]]$Message
    )
    BEGIN {}
    PROCESS {
        if ($Null -ne $Message) {
            $dt = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss")
            foreach ($item in $Message) {
                if ($item.length -gt 0) {
                    $it = $item -split '(.{1,70})' | Where-Object {$_}
                    $dt + ": " + $it[0] | Write-Host
                    $dt = $dt -replace '(.)',' '
                    $i = 1
                    while ($it[$i]) {
                        $dt + "  " + $it[$i] | Write-Host
                        $i++
                    }
                }
            }
        }
    }
    END {}
}

Now calling it with a string:

"----" | WriteToLog

gives:

2023-05-25 00:28:05: -
                     -
                     -
                     -
                     -

I'd expected:

2023-05-25 00:28:05: -----

Not splitting the string in characters.
With a string longer than 70 characters it works as expected:

"--------------------------------------------------------------------------" | WriteToLog

gives:

2023-05-25 00:32:37: ----------------------------------------------------------------------
                     ----

Any idea why this happens?

答案1

得分: 1

将您的正则表达式更改为 '(?<=\G.{70})',这样只有在字符计数为 70 时才会拆分,还使用了正向回顾与 \G,消除了过滤非空字符串的需要 (Where-Object { $_ })。另外,条件 if ($Null -ne $Message) 是不必要的,您已经在枚举集合并检查 if ($item.Length -gt 0)

function WriteToLog {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [AllowEmptyCollection()]
        [AllowEmptyString()]
        [string[]] $Message
    )

    process {
        $dt = (Get-Date).ToString('yyyy-MM-dd HH:mm:ss')
        foreach ($item in $Message) {
            if ($item.Length -gt 0) {
                $it = $item -split '(?<=\G.{70})'
                $dt + ': ' + $it[0] | Write-Host
                $dt = [string]::new(' ', $dt.Length)
                for($i = 1; $i -lt $it.Length; $i++) {
                    $dt + '  ' + $it[$i] | Write-Host
                }
            }
        }
    }
}

'---------------------------------------------------------------------------' | WriteToLog
'-----' | WriteToLog
WriteToLog '', ''
英文:

Change your regex to &#39;(?&lt;=\G.{70})&#39; so it only splits if the char count is 70, also using a positive lookbehind with \G removes the need to filter where the token is not an empty string (Where-Object { $_ }). Also the condition if ($Null -ne $Message) is unnecessary, you're already enumerating the collection and checking if ($item.Length -gt 0).

function WriteToLog {
    [CmdletBinding()]
    param(
        [Parameter(Mandatory, ValueFromPipeline)]
        [AllowEmptyCollection()]
        [AllowEmptyString()]
        [string[]] $Message
    )

    process {
        $dt = (Get-Date).ToString(&#39;yyyy-MM-dd HH:mm:ss&#39;)
        foreach ($item in $Message) {
            if ($item.Length -gt 0) {
                $it = $item -split &#39;(?&lt;=\G.{70})&#39;
                $dt + &#39;: &#39; + $it[0] | Write-Host
                $dt = [string]::new(&#39; &#39;, $dt.Length)
                for($i = 1; $i -lt $it.Length; $i++) {
                    $dt + &#39;  &#39; + $it[$i] | Write-Host
                }
            }
        }
    }
}

&#39;---------------------------------------------------------------------------&#39; | WriteToLog
&#39;-----&#39; | WriteToLog
WriteToLog &#39;&#39;, &#39;&#39;

huangapple
  • 本文由 发表于 2023年5月25日 06:39:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/76327822.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定