英文:
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 '(?<=\G.{70})'
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('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 '', ''
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论