如何将一系列连字符分隔的数字分别填充为两位数字



我对PowerShell编程还很陌生,所以需要帮助处理下面描述的一组字符串:

"14-2-1-1"
"14-2-1-1-1"
"14-2-1-1-10"

如果在19之间,我想在-之间的每个数字上加零。所以结果应该是:

"14-02-01-01"
"14-02-01-01-01"
"14-02-01-01-10"

我想出了以下代码,但想知道是否有更好/更快的解决方案。

$Filenum = "14-2-1-1"
$hicount = ($Filenum.ToCharArray() | Where-Object{$_ -eq '-'} | Measure-Object).Count
$FileNPad = ''
For ($i=0; $i -le $hicount; $i++) {
$Filesec= "{$i}" -f $Filenum.split('-')
If ([int]$Filesec -le 9)
{
$FileNPad = "$FileNPad-"+"0"+"$Filesec"
}
Else
{
$FileNPad="$FileNPad-$Filesec"
}
}
$FileNPad = $FileNPad.Trim("-"," ")

您可以简单地在-、padleft上拆分,然后与-重新连接在一起,而不是手动跟踪元素数量并检查每个值

"14-2-1-1","14-2-1-1-1","14-2-1-1-10" | ForEach-Object {
($_ -split '-').PadLeft(2,'0') -join '-'
}

哪个输出

14-02-01-01
14-02-01-01-01
14-02-01-01-10

我倾向于采用Doug Maurer的答案,因为它很清晰,但这里有另一种方法。下面的最后一节展示了一个解决方案,该解决方案可能同样清晰,但也有其自身的一些优势。

输入中的数字组模式

您的输入字符串由一个或多个组组成,其中每个组。。。

  1. 。。。包含一个或多个数字,并且
  2. 。。。前面是-或字符串的开头,并且
  3. 。。。后面跟一个CCD_ 7或字符串的末尾

需要插入前导"0"的组正好包含一位数字;也就是说,它们由。。。

  1. 。。。-或字符串的开头,后跟
  2. 。。。一个位数,后面跟
  3. 。。。CCD_ 10或字符串的末尾

使用-replace运算符替换个位数组

我们可以使用带有-replace运算符的正则表达式来定位该模式,并将单个数字替换为后面跟有相同数字的"0"。。。

'0-0-0-0', '00-00-00-00', '1-2-3-4', '01-02-03-04', '10-20-30-40', '11-22-33-44' |
ForEach-Object -Process { $_ -replace '(?<=-|^)(d)(?=-|$)', '0$1' }

其输出。。。

00-00-00-00
00-00-00-00
01-02-03-04
01-02-03-04
10-20-30-40
11-22-33-44

正如文档所描述的,-replace运算符是这样使用的。。。

<input> -replace <regular-expression>, <substitute>

匹配模式

匹配模式'(?<=-|^)(d)(?=-|$)'表示。。。

  • (?<=-|^)-或字符串开头的零宽度正后备断言
    • 换句话说,匹配但不捕获-或字符串的开头
  • (d):单个数字,捕获并可用替换$1
  • (?=-|$)-或字符串末尾的零宽度正向前瞻断言
    • 换句话说,匹配但不捕获-或字符串结尾

替换模式

替换图案'0$1'表示。。。

  • 文字文本'0',后面跟
  • 第一次捕获的值((d)(

使用[Regex]::Replace()和替换[String]替换个位数组

您也可以调用[Regex]类的staticReplace()方法来代替-replace运算符。。。

'0-0-0-0', '00-00-00-00', '1-2-3-4', '01-02-03-04', '10-20-30-40', '11-22-33-44' |
ForEach-Object -Process { [Regex]::Replace($_, '(?<=-|^)(d)(?=-|$)', '0$1') }

并且结果是相同的。

使用[Regex]::Replace()[MatchEvaluator]替换数字组

正则表达式和命令式解决方案的混合是调用Replace()方法的重载,该方法使用[MatchEvaluator]而不是替换[String]。。。

# This [ScriptBlock] will be passed to a [System.Text.RegularExpressions.MatchEvaluator] parameter
$matchEvaluator = {
# The [System.Text.RegularExpressions.Match] parameter
param($match)
# The replacement [String]
return $match.Value.PadLeft(2, '0')
}
'0-0-0-0', '00-00-00-00', '1-2-3-4', '01-02-03-04', '10-20-30-40', '11-22-33-44' |
ForEach-Object -Process { [Regex]::Replace($_, '(d+)', $matchEvaluator) }

这会产生与上面相同的结果。

[MatchEvaluator]是一个委托,它接受要替换的Match($match(,并返回要替换它的[String](左填充到两位的匹配文本(。还要注意,尽管上面我们只捕获独立的数字(d),但这里我们捕获一个或多个数字(d+)的所有组,并将其留给PadLeft()来确定是否需要前导"0"

我认为这是一个比正则表达式更令人信服的解决方案,因为它是其中最好的一个,也是命令式世界:

  • 它使用一个简单的正则表达式模式来定位输入字符串中的数字组
  • 它使用一个简单的[ScriptBlock]来转换输入字符串中的数字组
  • 通过不将输入字符串拆分,它不会创建那么多的中间字符串和数组垃圾
    • 如果没有基准测试,我不能说使用正则表达式是否掩盖了这种潜在的性能改进

最新更新