Regex 替换无效的文件名字符

Regex 替换无效的文件名字符,regex,powershell,Regex,Powershell,我想写一个小的实用程序函数,用破折号替换文件名中的任何禁止字符序列 例如: foo.txt==>foo.txt 一些字符串\o/==>一些字符串-o- https://stackoverflow.com/questions==>https stackoverflow.com问题 我这样写函数: function Get-SafeFileName{ param( [Parameter(Mandatory, Position=0, ValueFromPipeline)]

我想写一个小的实用程序函数,用破折号替换文件名中的任何禁止字符序列

例如:

  • foo.txt
    ==>
    foo.txt
  • 一些字符串\o/
    ==>
    一些字符串-o-
  • https://stackoverflow.com/questions
    ==>
    https stackoverflow.com问题
我这样写函数:

function Get-SafeFileName{
    param(
        [Parameter(Mandatory, Position=0, ValueFromPipeline)]
        [object]$Data
    )
    process {
    
        $pattern = "[" + [regex]::Escape([string][System.IO.Path]::GetInvalidFileNameChars()) +"]+"

        [regex]::Replace($Data, $pattern, "-")
    }
}
这是可行的,除了空格字符被替换,即使它是允许的字符

这是一个字符串
导致
这是一个字符串
,这是不必要的

如何解决这个问题

挖掘一点显示
[System.IO.Path]::GetInvalidFileNameChars()
不包含空格字符(ascii代码32)。但还有许多其他类似于“空间”的角色


也许正则表达式引擎没有看到区别?

首先,通过将无效字符列表转换为字符串(即字符类中出现空格的位置)来错误地转换无效字符列表

其次,您不能使用
Regex.Escape
来转义进入字符类的字符,因为这意味着转义字符必须是字符类之外的文字

解决办法是

function Get-SafeFileName{
    param(
        [Parameter(Mandatory, Position=0, ValueFromPipeline)]
        [object]$Data
    )
    process {
    
        $pattern = '[' + ([System.IO.Path]::GetInvalidFileNameChars() -join '').Replace('\','\\') + ']+'

        [regex]::Replace($Data, $pattern, "-")
    }
}
在字符类中需要转义的字符只有:

  • ^
  • -
  • \
  • ]

由于
GetInvalidFileNameChars()
只包含上述四个特殊字符中的一个,因此您可以只使用一个
.Replace('\','\')
而不是所有四个
.Replace('\','\').Replace('-','\-').Replace('^','\^').Replace(']','\]'))
我找到了另一种使用unicode结构的方法

function Get-SafeFileName{
    param(
        [Parameter(Mandatory, Position=0, ValueFromPipeline)]
        [object]$Data
    )
    process {
    
        $pattern = "[" + ( ([System.IO.Path]::GetInvalidFileNameChars() | % { "\x" + ([int]$_).ToString('X2') } ) -join '') +"]+"

        [regex]::Replace($Data, $pattern, "-")
    }
}
$pattern
现在是
[\x22\x3C\x3E\x7C\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x0C\x0D\x0E\x0F\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1A\x1B\x1C\x1D\x1E\x1E\x1F\x3A\x3A\x3A\x5C\x5f]+>


有了这一点,就没有什么模棱两可的了。标准空格不会被替换

您永远不应该使用
[regex]::Escape
来转义进入字符类的字符。您可以从另一个角度看它,并拥有一个允许的字符数组,如果不匹配,则替换为“-”?@WiktorStribiżew:我不明白you@DuchyWare:正则表达式很方便,因为有量词。特别是,我的正则表达式有一个leader
+
,它实际上将一系列禁止的字符重新保存到一个破折号上(如url示例中的
://
),请参见。不用于转义字符类中的字符。