如何从路径和文件名中删除非法字符?


456

我需要一种健壮且简单的方法来从简单的字符串中删除非法的路径和文件字符。我使用了下面的代码,但是它似乎什么也没做,我想念的是什么?

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();
        }
    }
}

1
修剪可删除字符串开头和结尾的字符。但是,您可能应该问为什么数据无效,而不是尝试清理/修复数据,而是拒绝数据。
user7116

8
Unix样式名称在Windows上无效,我不想处理8.3短名称。
加里·威洛比

GetInvalidFileNameChars()将从文件夹路径中删除诸如:\等内容。
CAD笨拙

1
Path.GetInvalidPathChars()似乎没有剥离*?
CAD猛击了

18
我测试了这个问题的五个答案(定时循环100,000),以下方法是最快的。正则表达式排在第二位,并且慢25%:public string GetSafeFilename(string filename){return string.Join(“ _”,filename.Split(Path.GetInvalidFileNameChars())); }
Brain2000 '16

Answers:


494

尝试这样的事情;

string illegal = "\"M\"\\a/ry/ h**ad:>> a\\/:*?\"| li*tt|le|| la\"mb.?";
string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());

foreach (char c in invalid)
{
    illegal = illegal.Replace(c.ToString(), ""); 
}

但是我必须同意这些意见,我可能会尝试处理非法路径的来源,而不是试图将非法路径变为合法但可能是意想不到的路径。

编辑:或者使用Regex的潜在“更好”的解决方案。

string illegal = "\"M\"\\a/ry/ h**ad:>> a\\/:*?\"| li*tt|le|| la\"mb.?";
string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch)));
illegal = r.Replace(illegal, "");

仍然有个问题要问,为什么首先要这样做。


40
不必将两个列表附加在一起。非法文件名字符列表包含非法路径字符列表,并且还有更多。这是强制转换为int的两个列表的列表:34,60,62,124,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,58,42,63,92,47 34,60,62,124,0,1,2 ,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27 ,28,29,30,31
萨雷尔·博塔

9
@sjbotha在Windows和Microsoft .NET的实现上可能是正确的,我不愿意对运行Linux的单声道做出相同的假设。
马修·沙利

7
关于第一个解决方案。StringBuilder是否应该比字符串分配更有效?
epignosisx 2011年

6
值得一提的是,@ MatthewScharley在非Windows平台上运行时,GetInvalidPathChars()的Mono实现仅返回0x00,GetInvalidFileNameChars()仅返回0x00和'/'。在Windows上,无效字符的列表要长得多,并且GetInvalidPathChars()在GetInvalidFileNameChars()中完全重复。在可预见的将来这不会改变,因此您真正要做的只是使此函数运行的时间加倍,因为您担心有效路径的定义很快就会改变。不会的。
沃伦·鲁马克

13
@Charleh的讨论是不必要的...应该始终对代码进行优化,并且不存在任何错误的风险。文件名也是路径的一部分。因此,GetInvalidPathChars()可能包含GetInvalidFileNameChars()不包含的字符只是不合逻辑的。您没有对“过早”的优化抱有正确的态度。您只是在使用错误的代码。
Stefan Fabian 2014年

352

最初提出的问题是“删除非法字符”:

public string RemoveInvalidChars(string filename)
{
    return string.Concat(filename.Split(Path.GetInvalidFileNameChars()));
}

您可能要替换它们:

public string ReplaceInvalidChars(string filename)
{
    return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));    
}

这个答案是在Ceres的另一个主题上,我真的很喜欢它简洁而简单。


10
要精确回答OP的问题,您需要使用“”而不是“ _”,但是您的答案实际上可能适用于我们中的更多人。我认为以某种合法字符替换非法字符更为常见。
BH

35
我从这个问题测试了五种方法(定时循环100,000),这是最快的一种方法。正则表达式排在第二位,比这种方法慢25%。
Brain2000 '16

10
要解决@BH的评论,只需使用string.Concat(name.Split(Path.GetInvalidFileNameChars()))
Michael Sutton

210

我使用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


4
这对我不起作用。该方法不返回干净字符串。它按原样返回传递的文件名。
卡兰

@Karan所说的,这不起作用,原始字符串返回。
2014年

实际上,你可以使用LINQ做这样虽然: var invalid = new HashSet<char>(Path.GetInvalidPathChars()); return new string(originalString.Where(s => !invalid.Contains(s)).ToArray())。性能可能不是很好,但这可能并不重要。
Casey 2015年

2
@Karan或Jon您正在发送什么输入此功能?请参阅我的编辑以验证此方法。
Michael Minton

3
这很容易-伙计们用有效的字符传递字符串。建议使用凉爽的骨料溶液。
Nickmaovich

89

您可以使用Linq删除非法字符,如下所示:

var invalidChars = Path.GetInvalidFileNameChars();

var invalidCharsRemoved = stringWithInvalidChars
.Where(x => !invalidChars.Contains(x))
.ToArray();

编辑
注释中提到的所需编辑的外观如下:

var invalidChars = Path.GetInvalidFileNameChars();

string invalidCharsRemoved = new string(stringWithInvalidChars
  .Where(x => !invalidChars.Contains(x))
  .ToArray());

1
我喜欢这种方式:您只在字符串中保留允许的字符(除了char数组外别无其他)。
Dude Pascalou 2012年

6
我知道这是一个古老的问题,但这是一个了不起的答案。但是,我想补充一点,在c#中,您不能从char []强制隐式或显式地转换为字符串(疯狂,我知道),因此您需要将其放入字符串构造函数中。
JNYRanger 2014年

1
我尚未确认这一点,但我希望Path.GetInvalidPathChars()是GetInvalidFileNameChars()的超集并覆盖文件名和路径,因此我可能会改用它。
angularsen 2015年

3
@anjdreas实际上,Path.GetInvalidPathChars()似乎是Path.GetInvalidFileNameChars()的子集,而不是相反。例如,Path.GetInvalidPathChars()将不会返回“?”。
拉斐尔·科斯塔

1
这是一个很好的答案。我同时使用文件名列表和文件路径列表:____________________________字符串cleanData =新字符串(data.Where(x =>!Path.GetInvalidFileNameChars()。包含(x)&&!Path.GetInvalidPathChars()。包含(x))。 ToArray());
goamn

27

这些都是不错的解决方案,但是它们都依赖Path.GetInvalidFileNameChars,可能不如您想像的那样可靠。请注意有关以下内容的MSDN文档中的以下说明Path.GetInvalidFileNameChars

从此方法返回的数组不能保证包含文件和目录名称中无效的完整字符集。无效字符的完整集合可能因文件系统而异。例如,在基于Windows的桌面平台上,无效的路径字符可能包括ASCII / Unicode字符1到31,以及引号(“),小于(<),大于(>),竖线(|),退格键( \ b),空(\ 0)和制表符(\ t)。

方法并没有更好Path.GetInvalidPathChars。它包含完全相同的注释。


13
那么,Path.GetInvalidFileNameChars有什么意义呢?我希望它完全返回当前系统的无效字符,依靠.NET知道我正在运行的文件系统,并向我展示合适的无效字符。如果不是这种情况,而只是返回硬编码的字符,这些字符首先是不可靠的,则应删除此方法,因为它的值为零。
1

1
我知道这是一个旧注释,但是@Jan您可能想在另一个文件系统上写,也许这就是为什么出现警告的原因。
fantastik78

3
@ fantastik78很好,但是在这种情况下,我希望有一个附加的enum参数来指定我的远程FS。如果这是过多的维护工作(很可能是这种情况),那么整个方法仍然不是一个好主意,因为它给您带来错误的安全印象。

1
@Jan我完全同意你的观点,我只是在警告这个话题。
fantastik78

有趣的是,这是一种“黑名单”无效字符。在这里只将已知的有效字符“列入白名单”会更好吗?我想起了愚蠢“virusscanner”的想法,而不是允许白名单应用....
伯恩哈德

26

对于文件名:

var cleanFileName = string.Join("", fileName.Split(Path.GetInvalidFileNameChars()));

对于完整路径:

var cleanPath = string.Join("", path.Split(Path.GetInvalidPathChars()));

请注意,如果打算将此功能用作安全功能,则更健壮的方法是扩展所有路径,然后验证用户提供的路径确实是用户应有权访问的目录的子级。


18

对于初学者,Trim仅从string的开头或结尾删除字符。其次,您应该评估您是否真的要删除令人反感的字符,或者快速失败并让用户知道其文件名无效。我的选择是后者,但我的答案至少应该向您展示如何正确和错误地做事:

显示如何检查给定字符串是否为有效文件名的StackOverflow问题。请注意,您可以使用此问题中的正则表达式删除带有正则表达式替换的字符(如果您确实需要这样做)。


我特别同意第二条建议。
OregonGhost

4
我通常同意第二种,但是我有一个程序可以生成文件名,在某些情况下可能包含非法字符。由于我的程序正在生成非法文件名,因此我认为删除/替换这些字符是适当的。(仅指出一个有效的用例)
JDB仍然记得Monica

16

从用户输入中删除非法字符的最佳方法是使用Regex类替换非法字符,在代码后面创建方法,或者使用RegularExpression控件在客户端进行验证。

public string RemoveSpecialCharacters(string str)
{
    return Regex.Replace(str, "[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled);
}

要么

<asp:RegularExpressionValidator ID="regxFolderName" 
                                runat="server" 
                                ErrorMessage="Enter folder name with  a-z A-Z0-9_" 
                                ControlToValidate="txtFolderName" 
                                Display="Dynamic" 
                                ValidationExpression="^[a-zA-Z0-9_]*$" 
                                ForeColor="Red">

5
恕我直言,此解决方案比其他解决方案要好得多。与其搜索所有无效字符,不如定义哪些有效字符。
igorushi

15

我使用正则表达式来实现这一目标。首先,我动态构建正则表达式。

string regex = string.Format(
                   "[{0}]",
                   Regex.Escape(new string(Path.GetInvalidFileNameChars())));
Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

然后,我只是调用removeInvalidChars.Replace进行查找和替换。显然,这也可以扩展为覆盖路径字符。


奇怪,它一直在为我工作。如果有机会,我会仔细检查。您能否更具体地说明到底什么对您不起作用?
杰夫·耶茨

1
因为您没有正确地转义路径字符,所以它不起作用(至少是正确的),并且其中一些具有特殊含义。请参阅我的答案以了解如何执行此操作。
马修·沙利

@Jeff:如果稍加修改,您的版本仍比Matthew的版本好。请参阅我的回答。
1

2
我还将添加一些可以在MSDN上找到的其他无效文件名模式,并将您的解决方案扩展到以下正则表达式:new Regex(String.Format("^(CON|PRN|AUX|NUL|CLOCK\$|COM[1-9]|LPT[1-9])(?=\..|$)|(^(\.+|\s+)$)|((\.+|\s+)$)|([{0}])", Regex.Escape(new String(Path.GetInvalidFileNameChars()))), RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.CultureInvariant);
yar_shukan 2014年

13

我绝对更喜欢杰夫·耶茨的想法。如果您稍作修改,它将可以完美地工作:

string regex = String.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars())));
Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

改进只是为了逃避自动生成的正则表达式。


11

这是一个对.NET 3及更高版本有所帮助的代码段。

using System.IO;
using System.Text.RegularExpressions;

public static class PathValidation
{
    private static string pathValidatorExpression = "^[^" + string.Join("", Array.ConvertAll(Path.GetInvalidPathChars(), x => Regex.Escape(x.ToString()))) + "]+$";
    private static Regex pathValidator = new Regex(pathValidatorExpression, RegexOptions.Compiled);

    private static string fileNameValidatorExpression = "^[^" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]+$";
    private static Regex fileNameValidator = new Regex(fileNameValidatorExpression, RegexOptions.Compiled);

    private static string pathCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidPathChars(), x => Regex.Escape(x.ToString()))) + "]";
    private static Regex pathCleaner = new Regex(pathCleanerExpression, RegexOptions.Compiled);

    private static string fileNameCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]";
    private static Regex fileNameCleaner = new Regex(fileNameCleanerExpression, RegexOptions.Compiled);

    public static bool ValidatePath(string path)
    {
        return pathValidator.IsMatch(path);
    }

    public static bool ValidateFileName(string fileName)
    {
        return fileNameValidator.IsMatch(fileName);
    }

    public static string CleanPath(string path)
    {
        return pathCleaner.Replace(path, "");
    }

    public static string CleanFileName(string fileName)
    {
        return fileNameCleaner.Replace(fileName, "");
    }
}

8

上面的大多数解决方案都为路径和文件名组合了非法字符,这是错误的(即使当前两个调用都返回相同的字符集)。我首先将path + filename拆分为path和filename,然后将适当的设置应用于其中的一个,然后再次将其合并。

wvd_vegt


+1:非常正确。如今,在.NET 4.0中工作时,最重要的正则表达式解决方案在完整路径中消除了所有反斜杠。因此,我为目录路径制作了一个正则表达式,而为文件名制作了一个正则表达式,分别进行了清理和重新组合
dario_ramos 2013年

可能是正确的,但这不能回答问题。与这里已经存在的一些完整解决方案相比,我不确定模糊的“我愿意那样做”是否会非常有用(例如,参见下面的礼来的回答)
Ian Grainger

6

如果删除或用单个字符替换无效字符,则可能会发生冲突:

<abc -> abc
>abc -> abc

这是避免这种情况的简单方法:

public static string ReplaceInvalidFileNameChars(string s)
{
    char[] invalidFileNameChars = System.IO.Path.GetInvalidFileNameChars();
    foreach (char c in invalidFileNameChars)
        s = s.Replace(c.ToString(), "[" + Array.IndexOf(invalidFileNameChars, c) + "]");
    return s;
}

结果:

 <abc -> [1]abc
 >abc -> [2]abc

5

引发异常。

if ( fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 )
            {
                throw new ArgumentException();
            }

4

我写这个怪物很有趣,它可以让您往返:

public static class FileUtility
{
    private const char PrefixChar = '%';
    private static readonly int MaxLength;
    private static readonly Dictionary<char,char[]> Illegals;
    static FileUtility()
    {
        List<char> illegal = new List<char> { PrefixChar };
        illegal.AddRange(Path.GetInvalidFileNameChars());
        MaxLength = illegal.Select(x => ((int)x).ToString().Length).Max();
        Illegals = illegal.ToDictionary(x => x, x => ((int)x).ToString("D" + MaxLength).ToCharArray());
    }

    public static string FilenameEncode(string s)
    {
        var builder = new StringBuilder();
        char[] replacement;
        using (var reader = new StringReader(s))
        {
            while (true)
            {
                int read = reader.Read();
                if (read == -1)
                    break;
                char c = (char)read;
                if(Illegals.TryGetValue(c,out replacement))
                {
                    builder.Append(PrefixChar);
                    builder.Append(replacement);
                }
                else
                {
                    builder.Append(c);
                }
            }
        }
        return builder.ToString();
    }

    public static string FilenameDecode(string s)
    {
        var builder = new StringBuilder();
        char[] buffer = new char[MaxLength];
        using (var reader = new StringReader(s))
        {
            while (true)
            {
                int read = reader.Read();
                if (read == -1)
                    break;
                char c = (char)read;
                if (c == PrefixChar)
                {
                    reader.Read(buffer, 0, MaxLength);
                    var encoded =(char) ParseCharArray(buffer);
                    builder.Append(encoded);
                }
                else
                {
                    builder.Append(c);
                }
            }
        }
        return builder.ToString();
    }

    public static int ParseCharArray(char[] buffer)
    {
        int result = 0;
        foreach (char t in buffer)
        {
            int digit = t - '0';
            if ((digit < 0) || (digit > 9))
            {
                throw new ArgumentException("Input string was not in the correct format");
            }
            result *= 10;
            result += digit;
        }
        return result;
    }
}

1
我喜欢它,因为它避免了两个不同的字符串创建相同的结果路径。
2014年

3

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

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


鉴于.net是一个旨在允许程序在多个平台(例如Linux / Unix以及Windows)上运行的框架,我认为Path.GetInvalidFileNameChars()最好,因为它将包含关于什么是或不是的知识。在运行程序的文件系统上有效。即使您的程序永远不会在Linux上运行(也许已满是WPF代码),将来总会有一些新的Windows文件系统出现并具有不同的有效/无效字符的机会。用regex自己动手会彻底改变方向,并将平台问题转移到您自己的代码中。
丹尼尔·斯科特

我同意您对在线正则表达式编辑器/测试器的建议。我发现它们非常宝贵(因为正则表达式是棘手的事情,并且充满了微妙的细节,可以使您轻易绊倒,使您的正则表达式在出现极端情况时表现出某种出乎意料的方式)。我最喜欢的是regex101.com(我喜欢它如何分解正则表达式并清楚地向您展示它期望匹配的内容)。我也很喜欢debuggex.com,因为它具有匹配组和字符类以及诸如此类的紧凑可视表示。
丹尼尔·斯科特

3

这似乎是O(n),并且不会在字符串上花费过多的内存:

    private static readonly HashSet<char> invalidFileNameChars = new HashSet<char>(Path.GetInvalidFileNameChars());

    public static string RemoveInvalidFileNameChars(string name)
    {
        if (!name.Any(c => invalidFileNameChars.Contains(c))) {
            return name;
        }

        return new string(name.Where(c => !invalidFileNameChars.Contains(c)).ToArray());
    }

1
当您使用“任何”功能时,我认为它不是O(n)。
II ARROWS'Aug

@IIARROWS,您认为这是什么?
Alexey F

我不知道,当我写评论时,并没有那种感觉……现在,我试图计算它,看来您是对的。
II ARROWS'Aug

出于您对性能的考虑,我选择了这一款。谢谢。
Berend Engelbrecht

3

在这里浏览答案时,它们全都**涉及使用无效文件名字符的char数组。

当然,这可能是微优化的,但是对于那些希望检查大量值是否为有效文件名的人来说,值得注意的是,构建无效字符的哈希集将带来明显更好的性能。

过去,我非常惊讶(震惊)哈希集(或字典)在列表上进行迭代的速度有多快。对于字符串,这是一个非常低的数字(内存中大约有5-7个项目)。使用大多数其他简单数据(对象引用,数字等),神奇的转换似乎大约有20个项目。

Path.InvalidFileNameChars“列表”中有40个无效字符。今天进行了搜索,并且在StackOverflow上有一个很好的基准,它显示哈希集将花费40个项目的数组/列表一半的时间:https ://stackoverflow.com/a/10762995/949129

这是我用于清理路径的帮助程序类。我现在忘记了为什么要使用花哨的更换选项,但这是一个可爱的奖励。

额外的奖励方法“ IsValidLocalPath”也是:)

(**不使用正则表达式的那些)

public static class PathExtensions
{
    private static HashSet<char> _invalidFilenameChars;
    private static HashSet<char> InvalidFilenameChars
    {
        get { return _invalidFilenameChars ?? (_invalidFilenameChars = new HashSet<char>(Path.GetInvalidFileNameChars())); }
    }


    /// <summary>Replaces characters in <c>text</c> that are not allowed in file names with the 
    /// specified replacement character.</summary>
    /// <param name="text">Text to make into a valid filename. The same string is returned if 
    /// it is valid already.</param>
    /// <param name="replacement">Replacement character, or NULL to remove bad characters.</param>
    /// <param name="fancyReplacements">TRUE to replace quotes and slashes with the non-ASCII characters ” and ⁄.</param>
    /// <returns>A string that can be used as a filename. If the output string would otherwise be empty, "_" is returned.</returns>
    public static string ToValidFilename(this string text, char? replacement = '_', bool fancyReplacements = false)
    {
        StringBuilder sb = new StringBuilder(text.Length);
        HashSet<char> invalids = InvalidFilenameChars;
        bool changed = false;

        for (int i = 0; i < text.Length; i++)
        {
            char c = text[i];
            if (invalids.Contains(c))
            {
                changed = true;
                char repl = replacement ?? '\0';
                if (fancyReplacements)
                {
                    if (c == '"') repl = '”'; // U+201D right double quotation mark
                    else if (c == '\'') repl = '’'; // U+2019 right single quotation mark
                    else if (c == '/') repl = '⁄'; // U+2044 fraction slash
                }
                if (repl != '\0')
                    sb.Append(repl);
            }
            else
                sb.Append(c);
        }

        if (sb.Length == 0)
            return "_";

        return changed ? sb.ToString() : text;
    }


    /// <summary>
    /// Returns TRUE if the specified path is a valid, local filesystem path.
    /// </summary>
    /// <param name="pathString"></param>
    /// <returns></returns>
    public static bool IsValidLocalPath(this string pathString)
    {
        // From solution at https://stackoverflow.com/a/11636052/949129
        Uri pathUri;
        Boolean isValidUri = Uri.TryCreate(pathString, UriKind.Absolute, out pathUri);
        return isValidUri && pathUri != null && pathUri.IsLoopback;
    }
}

2
public static class StringExtensions
      {
        public static string RemoveUnnecessary(this string source)
        {
            string result = string.Empty;
            string regex = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
            Regex reg = new Regex(string.Format("[{0}]", Regex.Escape(regex)));
            result = reg.Replace(source, "");
            return result;
        }
    }

您可以清楚地使用方法。


2

文件名不能包含Path.GetInvalidPathChars()+#符号以及其他特定名称中的字符。我们将所有支票合并为一类:

public static class FileNameExtensions
{
    private static readonly Lazy<string[]> InvalidFileNameChars =
        new Lazy<string[]>(() => Path.GetInvalidPathChars()
            .Union(Path.GetInvalidFileNameChars()
            .Union(new[] { '+', '#' })).Select(c => c.ToString(CultureInfo.InvariantCulture)).ToArray());


    private static readonly HashSet<string> ProhibitedNames = new HashSet<string>
    {
        @"aux",
        @"con",
        @"clock$",
        @"nul",
        @"prn",

        @"com1",
        @"com2",
        @"com3",
        @"com4",
        @"com5",
        @"com6",
        @"com7",
        @"com8",
        @"com9",

        @"lpt1",
        @"lpt2",
        @"lpt3",
        @"lpt4",
        @"lpt5",
        @"lpt6",
        @"lpt7",
        @"lpt8",
        @"lpt9"
    };

    public static bool IsValidFileName(string fileName)
    {
        return !string.IsNullOrWhiteSpace(fileName)
            && fileName.All(o => !IsInvalidFileNameChar(o))
            && !IsProhibitedName(fileName);
    }

    public static bool IsProhibitedName(string fileName)
    {
        return ProhibitedNames.Contains(fileName.ToLower(CultureInfo.InvariantCulture));
    }

    private static string ReplaceInvalidFileNameSymbols([CanBeNull] this string value, string replacementValue)
    {
        if (value == null)
        {
            return null;
        }

        return InvalidFileNameChars.Value.Aggregate(new StringBuilder(value),
            (sb, currentChar) => sb.Replace(currentChar, replacementValue)).ToString();
    }

    public static bool IsInvalidFileNameChar(char value)
    {
        return InvalidFileNameChars.Value.Contains(value.ToString(CultureInfo.InvariantCulture));
    }

    public static string GetValidFileName([NotNull] this string value)
    {
        return GetValidFileName(value, @"_");
    }

    public static string GetValidFileName([NotNull] this string value, string replacementValue)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentException(@"value should be non empty", nameof(value));
        }

        if (IsProhibitedName(value))
        {
            return (string.IsNullOrWhiteSpace(replacementValue) ? @"_" : replacementValue) + value; 
        }

        return ReplaceInvalidFileNameSymbols(value, replacementValue);
    }

    public static string GetFileNameError(string fileName)
    {
        if (string.IsNullOrWhiteSpace(fileName))
        {
            return CommonResources.SelectReportNameError;
        }

        if (IsProhibitedName(fileName))
        {
            return CommonResources.FileNameIsProhibited;
        }

        var invalidChars = fileName.Where(IsInvalidFileNameChar).Distinct().ToArray();

        if(invalidChars.Length > 0)
        {
            return string.Format(CultureInfo.CurrentCulture,
                invalidChars.Length == 1 ? CommonResources.InvalidCharacter : CommonResources.InvalidCharacters,
                StringExtensions.JoinQuoted(@",", @"'", invalidChars.Select(c => c.ToString(CultureInfo.CurrentCulture))));
        }

        return string.Empty;
    }
}

方法GetValidFileName将所有不正确的数据替换为_


2

一种用于清除Windows文件命名中任何非法字符的字符串的方法:

public static string CleanIllegalName(string p_testName) => new Regex(string.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars())))).Replace(p_testName, "");

1
public static bool IsValidFilename(string testName)
{
    return !new Regex("[" + Regex.Escape(new String(System.IO.Path.GetInvalidFileNameChars())) + "]").IsMatch(testName);
}

0

这样就可以满足您的需要,避免碰撞

 static string SanitiseFilename(string key)
    {
        var invalidChars = Path.GetInvalidFileNameChars();
        var sb = new StringBuilder();
        foreach (var c in key)
        {
            var invalidCharIndex = -1;
            for (var i = 0; i < invalidChars.Length; i++)
            {
                if (c == invalidChars[i])
                {
                    invalidCharIndex = i;
                }
            }
            if (invalidCharIndex > -1)
            {
                sb.Append("_").Append(invalidCharIndex);
                continue;
            }

            if (c == '_')
            {
                sb.Append("__");
                continue;
            }

            sb.Append(c);
        }
        return sb.ToString();

    }

0

我认为问题尚未完全解决。答案仅描述了干净的文件名或路径。这是我的解决方案:

private static string CleanPath(string path)
{
    string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
    Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch)));
    List<string> split = path.Split('\\').ToList();
    string returnValue = split.Aggregate(string.Empty, (current, s) => current + (r.Replace(s, "") + @"\"));
    returnValue = returnValue.TrimEnd('\\');
    return returnValue;
}

0

我创建了一个扩展方法,该方法结合了一些建议:

  1. 在哈希集中保存非法字符
  2. 过滤出ascii 127以下的字符。由于Path.GetInvalidFileNameChars不包含0到255之间的ascii代码可能包含的所有无效字符。请参见此处MSDN。
  3. 定义替换字符的可能性

资源:

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();
    }
}

0

这是一个用替换字符替换文件名中所有非法字符的函数:

public static string ReplaceIllegalFileChars(string FileNameWithoutPath, char ReplacementChar)
{
  const string IllegalFileChars = "*?/\\:<>|\"";
  StringBuilder sb = new StringBuilder(FileNameWithoutPath.Length);
  char c;

  for (int i = 0; i < FileNameWithoutPath.Length; i++)
  {
    c = FileNameWithoutPath[i];
    if (IllegalFileChars.IndexOf(c) >= 0)
    {
      c = ReplacementChar;
    }
    sb.Append(c);
  }
  return (sb.ToString());
}

例如,下划线可以用作替换字符:

NewFileName = ReplaceIllegalFileChars(FileName, '_');

除了您提供的答案之外,请考虑简要说明为什么以及如何解决此问题。
jtate

-7

或者你可以做

[YOUR STRING].Replace('\\', ' ').Replace('/', ' ').Replace('"', ' ').Replace('*', ' ').Replace(':', ' ').Replace('?', ' ').Replace('<', ' ').Replace('>', ' ').Replace('|', ' ').Trim();
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.