我需要一个强大的和简单的方法来删除非法的路径和文件字符从一个简单的字符串。我已经使用了下面的代码,但它似乎没有做任何事情,我错过了什么?

using System;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string illegal = "\"M<>\"\\a/ry/ h**ad:>> a\\/:*?\"<>| li*tt|le|| la\"mb.?";

            illegal = illegal.Trim(Path.GetInvalidFileNameChars());
            illegal = illegal.Trim(Path.GetInvalidPathChars());

            Console.WriteLine(illegal);
            Console.ReadLine();
        }
    }
}

当前回答

我已经滚动了我自己的方法,这似乎要快得多的其他张贴在这里(特别是正则表达式是如此缓慢),但我没有测试所有张贴的方法。

https://dotnetfiddle.net/haIXiY

第一个方法(我的)和第二个方法(也是我的,但旧的)也对反斜杠进行了额外的检查,所以基准测试并不完美,但无论如何,这只是给你一个想法。

在我的笔记本电脑上的结果(10万次迭代):

StringHelper.RemoveInvalidCharacters 1: 451 ms  
StringHelper.RemoveInvalidCharacters 2: 7139 ms  
StringHelper.RemoveInvalidCharacters 3: 2447 ms  
StringHelper.RemoveInvalidCharacters 4: 3733 ms  
StringHelper.RemoveInvalidCharacters 5: 11689 ms  (==> Regex!)

最快的方法:

public static string RemoveInvalidCharacters(string content, char replace = '_', bool doNotReplaceBackslashes = false)
{
    if (string.IsNullOrEmpty(content))
        return content;

    var idx = content.IndexOfAny(InvalidCharacters);
    if (idx >= 0)
    {
        var sb = new StringBuilder(content);
        while (idx >= 0)
        {
            if (sb[idx] != '\\' || !doNotReplaceBackslashes)
                sb[idx] = replace;
            idx = content.IndexOfAny(InvalidCharacters, idx+1);
        }
        return sb.ToString();
    }
    return content;
}

方法没有“按原样”编译InvalidCharacters属性,请检查fiddle是否有完整代码

其他回答

我已经滚动了我自己的方法,这似乎要快得多的其他张贴在这里(特别是正则表达式是如此缓慢),但我没有测试所有张贴的方法。

https://dotnetfiddle.net/haIXiY

第一个方法(我的)和第二个方法(也是我的,但旧的)也对反斜杠进行了额外的检查,所以基准测试并不完美,但无论如何,这只是给你一个想法。

在我的笔记本电脑上的结果(10万次迭代):

StringHelper.RemoveInvalidCharacters 1: 451 ms  
StringHelper.RemoveInvalidCharacters 2: 7139 ms  
StringHelper.RemoveInvalidCharacters 3: 2447 ms  
StringHelper.RemoveInvalidCharacters 4: 3733 ms  
StringHelper.RemoveInvalidCharacters 5: 11689 ms  (==> Regex!)

最快的方法:

public static string RemoveInvalidCharacters(string content, char replace = '_', bool doNotReplaceBackslashes = false)
{
    if (string.IsNullOrEmpty(content))
        return content;

    var idx = content.IndexOfAny(InvalidCharacters);
    if (idx >= 0)
    {
        var sb = new StringBuilder(content);
        while (idx >= 0)
        {
            if (sb[idx] != '\\' || !doNotReplaceBackslashes)
                sb[idx] = replace;
            idx = content.IndexOfAny(InvalidCharacters, idx+1);
        }
        return sb.ToString();
    }
    return content;
}

方法没有“按原样”编译InvalidCharacters属性,请检查fiddle是否有完整代码

我使用Linq来清理文件名。您也可以很容易地扩展它来检查有效路径。

private static string CleanFileName(string fileName)
{
    return Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty));
}

更新

一些评论指出这个方法不适合他们,所以我包含了一个到DotNetFiddle片段的链接,这样你就可以验证这个方法了。

https://dotnetfiddle.net/nw1SWY

上面的大多数解决方案都将路径和文件名的非法字符组合在一起,这是错误的(即使两个调用当前返回相同的字符集)。我将首先在path和filename中分割path+filename,然后应用适当的集,如果它们,然后再次结合两者。

wvd_vegt

我认为使用正则表达式验证并指定允许哪些字符要容易得多,而不是试图检查所有坏字符。 请看这些链接: http://www.c-sharpcorner.com/UploadFile/prasad_1/RegExpPSD12062005021717AM/RegExpPSD.aspx http://www.windowsdevcenter.com/pub/a/oreilly/windows/news/csharp_0101.html

另外,搜索一下“正则表达式编辑器”,它们很有帮助。有一些甚至可以为你输出c#代码。

我创建了一个扩展方法,它结合了几个建议:

在哈希集中保存非法字符 过滤ascii 127以下的字符。因为路径。getinvalidfilenamecars不包括ascii码从0到255的所有无效字符。看这里和MSDN 定义替换字符的可能性

来源:

public static class FileNameCorrector
{
    private static HashSet<char> invalid = new HashSet<char>(Path.GetInvalidFileNameChars());

    public static string ToValidFileName(this string name, char replacement = '\0')
    {
        var builder = new StringBuilder();
        foreach (var cur in name)
        {
            if (cur > 31 && cur < 128 && !invalid.Contains(cur))
            {
                builder.Append(cur);
            }
            else if (replacement != '\0')
            {
                builder.Append(replacement);
            }
        }

        return builder.ToString();
    }
}