2016-11-04 77 views
3

我已经编写了我自己的CSS缩放器,用于获得乐趣和利润(不是太多的利润),而且效果很好。我现在试图简化它,因为我基本上过滤了文件10次以上。对于一个小文件来说不是一个大问题,但是他们得到的数据越大,性能受到的影响就越大。Powershell中的正则表达式,结合替换调用

是否有更优雅的方式来过滤我的输入文件?我假设正则表达式将会有一个办法,但我没有正则表达式的向导......

$a = (gc($path + $file) -Raw) 
$a = $a -replace "\s{2,100}(?<!\S)", "" 
$a = $a -replace " {", "{" 
$a = $a -replace "} ", "}" 
$a = $a -replace " \(", "\(" 
$a = $a -replace "\) ", "\)" 
$a = $a -replace " \[", "\[" 
$a = $a -replace "\] ", "\]" 
$a = $a -replace ": ", ":" 
$a = $a -replace "; ", ";" 
$a = $a -replace ", ", "," 
$a = $a -replace "\n", "" 
$a = $a -replace "\t", "" 

为了节省您的头痛,我基本上使用第一-replace剥离方式由2-任何连续witespace长度为100个字符。 其余的替换陈述包括在特定情况下清理单个空间。

我该如何结合这个,所以我没有过滤文件12次?

+0

我建议尝试使用字符串*方法*来替换字符串'$ a = $ a.replace(')','')'并测量时间。即使在大型文本中,如果结果比任何基于正则表达式的答案都快,也不要感到惊讶。无论如何,你应该使用适当的CSS解析。 – wOxxOm

回答

3
  1. negative lookbehind(?<!\S)在这种情况下使用:(?<!prefix)thing以匹配不对左前缀的事情。当你把它放在正则表达式的末尾,没有任何事情发生时,我认为它什么也不做。你可能打算把它放在左边,或者可能打算成为一个负面看前面,我不会猜测,我只是删除它的这个答案。

  2. 您错过了character classes的使用。 abc寻找文字abc,但将它们放在方括号内,并且[abc]寻找任何字符a,b,c

    1. 使用它,可以将最后两行合并为一个:[\n\t],它可以替换换行符或制表符。
  3. 您可以结合两个独立使用正则表达式的逻辑OR |做一个匹配(什么也没有更换)规则:\s{2,100}|[\n\t] - 匹配空格或换行或制表符。 (你可以使用OR两次而不是字符,fwiw)。

  4. 使用regex capture groups它允许您引用无论正则表达式匹配,而无需事先知道那是什么。

    1. 例如, "space bracket -> bracket""space colon -> colon""space comma -> comma"都遵循一般模式"space (thing) -> (thing)"。和尾随空格"(thing) space -> (thing)"一样。

    2. 将带有字符类的捕获组合并为其余的行全部合并为一个。

例如

$a -replace " (:)", '$1' # capture the colon, replacement is not ':' 
          # it is "whatever was in the capture group" 

$a -replace " ([:,])", '$1' # capture the colon, or comma. Replacement 
          # is "whatever was in the capture group" 
          # space colon -> colon, space comma -> comma 

# make the space optional with \s{0,1} and put it at the start and end 
\s{0,1}([:,])\s{0,1} #now it will match "space (thing)" or "(thing) space" 

# Add in the rest of the characters, with appropriate \ escapes 
# gained from [regex]::Escape('those chars here') 

# Your original: 
$a = (gc D:\css\1.css -Raw) 
$a = $a -replace "\s{2,100}(?<!\S)", "" 
$a = $a -replace " {", "{" 
$a = $a -replace "} ", "}" 
$a = $a -replace " \(", "\(" 
$a = $a -replace "\) ", "\)" 
$a = $a -replace " \[", "\[" 
$a = $a -replace "\] ", "\]" 
$a = $a -replace ": ", ":" 
$a = $a -replace "; ", ";" 
$a = $a -replace ", ", "," 
$a = $a -replace "\n", "" 
$a = $a -replace "\t", "" 

# My version: 
$b = gc d:\css\1.css -Raw 
$b = $b -replace "\s{2,100}|[\n\t]", "" 
$b = $b -replace '\s{0,1}([])}{([:;,])\s{0,1}', '$1' 

# Test that they both do the same thing on my random downloaded sample file: 
$b -eq $a 

# Yep. 

再次做到这一点与其他|到两成一个组合:

$c = gc d:\css\1.css -Raw 
$c = $c -replace "\s{2,100}|[\n\t]|\s{0,1}([])}{([:;,])\s{0,1}", '$1' 

$c -eq $a # also same output as your original. 

NB. that the space and tab and newline capture nothing, so '$1' is empty, 
    which removes them. 

而且你可以花费大量的时间建立自己的不可读的正则表达式这可能不会明显快于任何实际场景。 :)

NB。 '$1'在替换中,美元是.Net正则表达式引擎的语法,而不是PowerShell变量。如果你使用双引号,PowerShell将从变量$ 1中插入字符串,并且可能不会替换它。

+0

太棒了。谢谢你的帮助,@TessellatingHeckler!这工作完美,现在看起来好多了! –

1

您可以将捕获组类似的模式加入到1个较大的表达式中,并在Regex替换方法中使用回调,您可以在其中评估匹配结构并使用适当的操作。

这里是为您的方案的解决方案,你可以扩展:

$callback = { param($match) 
    if ($match.Groups[1].Success -eq $true) { "" } 
    else { 
    if ($match.Groups[2].Success -eq $true) { $match.Groups[2].Value } 
    else { 
     if ($match.Groups[3].Success -eq $true) { $match.Groups[3].Value } 
     else { 
     if ($match.Groups[4].Success -eq $true) { $match.Groups[4].Value } 
     } 
    } 
    } 
} 
$path = "d:\input\folder\" 
$file = "input_file.txt" 
$a = [IO.File]::ReadAllText($path + $file) 
$rx = [regex]'(\s{2,100}(?<!\S)|[\n\t])|\s+([{([])|([])}])\s+|([:;,])\s+' 
$rx.Replace($a, $callback) | Out-File "d:\result\file.txt" 

图案的详细资料

  • (\s{2,100}(?<!\S)|[\n\t]) - 第1组拍摄之前没有与非空白2-100空格char(也许这个lookbehind是多余的)或换行符或制表符char
  • | - 或
  • \s+([{([]) - 只是匹配的一个或多个空格(\s+),然后捕捉到第2组从[{([]字符类中的任何单个字符:{([
  • |([])}])\s+ - 或第3组从[])}]字符捕获任何单个字符类:})],然后只匹配的一个或多个空格
  • |([:;,])\s+ - 或第4组从[:;,]焦炭类(:;,)和一个或多个捕获的任何焦炭whitesp尖子。
+0

回调方法比OP的10次重复要慢得多,因为在PowerShell中脚本块的调用开销非常大,而且这个特殊的调用会被调用很多。 – wOxxOm

+0

我不坚持这是最好的方法,我只是做了OP代码分析的第一步。如果我有更多的时间,我会像接受的答案那样达到更高的抽象层次。如果您无法获得单个反向引用替换,这将是唯一有效的方法。 –

+0

正确的解析似乎是唯一有效的方法。蛮力正则表达式在边界情况下会失败,像内部带括号的内容属性。无论如何,我的意思是,可以使用[regex] :: matches来代替慢回调,而通过while或foreach语句可以使用更快的正常循环。 – wOxxOm