替换无效的文件名字符。

3

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

例如:

  • foo.txt ==> foo.txt
  • Some string \o/ ==> Some string -o-
  • https://stackoverflow.com/questions ==> https-stackoverflow.com-questions

我像这样编写函数:

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

        [regex]::Replace($Data, $pattern, "-")
    }
}

这个代码可以工作,但空格字符被替换了,即使它是一个允许的字符。

This is a string 会变成 This-is-a-string,这并不是必要的。

怎么解决呢?

深入探究后发现,[System.IO.Path]::GetInvalidFileNameChars() 不包含空格字符(ASCII码32),但还有其它很多类似空格的字符。

也许正则表达式引擎看不到这些细微的差别?


你不应该使用[regex]::Escape来转义进入字符类的字符。 - Wiktor Stribiżew
1
你可以从另一个角度考虑,使用允许字符的数组,如果不匹配则用“-”替换吗? - DuchyWare
@WiktorStribiżew:我不明白你的意思。 - Steve B
@DuchyWare:正则表达式非常方便,因为它有量词。特别是,我的正则表达式有一个前导符号“+”,它实际上将一系列禁止字符替换为单个破折号(例如URL示例中的“://”)。 - Steve B
@SteveB 哦,是的,我错过了那个要求。 - DuchyWare
1
请见以下代码链接Regex.Escape 不应用于转义字符类中的字符。 - Wiktor Stribiżew
2个回答

2
首先,你将无效字符列表转换为字符串时出现了错误,这就是字符类中出现空格的原因。
其次,你不能使用 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(']','\]')


0

我发现了另一种使用 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\x1F\x3A\x2A\x3F\x5C\x2F]+

这样就没有歧义了。标准空格不会被替换。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接