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

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

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

尝试这样的事情,而不是;

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

但是我必须同意这些意见,我可能会试图处理非法path的来源,而不是试图将非法path捣毁成为合法但可能是非预期的path。

编辑:或使用正则expression式的潜在“更好”的解决scheme。

 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, ""); 

不过,这个问题还是要问,为什么你要这样做呢。

我使用Linq来清理文件名。 你可以很容易地扩展这个来检查有效的path。

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

更新

一些注释表明这种方法不适用于他们,所以我已经包含了一个DotNetFiddle片段的链接,所以你可以validation这个方法。

https://dotnetfiddle.net/nw1SWY

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

这个答案是由Ceres的另一个线程 ,我真的很喜欢它整洁和简单。

你可以像这样使用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()); 

这些都是很好的解决scheme,但都依赖于Path.GetInvalidFileNameChars ,这可能不如您想象的那样可靠。 请注意Path.GetInvalidFileNameChars的MSDN文档中的以下注释:

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

Path.GetInvalidPathChars方法不是更好。 它包含完全相同的评论。

对于初学者, 修剪只从string的开头或结尾删除字符 。 其次,你应该评估你是否真的想删除冒犯的angular色,或者快速失败,让用户知道他们的文件名是无效的。 我的select是后者,但我的回答至less应该告诉你如何做正确和错误的方式:

显示如何检查给定的string是否是有效的文件名的StackOverflow问题 。 请注意,您可以使用这个问题的正则expression式去除正则expression式replace字符(如果你真的需要这样做)。

我使用正则expression式来实现这一点。 首先,我dynamic地构build正则expression式。

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

然后,我只是调用removeInvalidChars.Replace来执行查找和replace。 这显然可以扩展到覆盖path字符。

我绝对喜欢Jeff Yates的想法。 如果你稍微修改它,它将工作得很好:

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

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

对于文件名称:

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

对于完整path:

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

从用户input中删除非法字符的最好方法是用Regex类replace非法字符,在后面的代码中创build方法,或者使用RegularExpression控件在客户端validation。

 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 az A-Z0-9_" ControlToValidate="txtFolderName" Display="Dynamic" ValidationExpression="^[a-zA-Z0-9_]*$" ForeColor="Red"> 

这是一个代码片段,应该有助于.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, ""); } } 

上面的大多数解决scheme将path和文件名错误的非法字符组合在一起(即使两个调用当前都返回同一组字符)。 我将首先拆分path和文件名中的path+文件名,然后将相应的集合应用于它们,然后将它们再次合并。

wvd_vegt

抛出exception。

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

如果您删除或replace单个字符的无效字符,您可以有冲突:

 <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 

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

另外,做一个“正则expression式编辑器”的search,他们帮助很多。 有一些甚至输出在C#代码为您。

我写这个怪物是为了好玩,它可以让你往返:

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

这似乎是O(N),并没有花太多的内存在string上:

  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()); } 
 public static bool IsValidFilename(string testName) { return !new Regex("[" + Regex.Escape(new String(System.IO.Path.GetInvalidFileNameChars())) + "]").IsMatch(testName); } 

这将做你想要的,并避免碰撞

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

我认为这个问题已经没有完整的答案…答案只描述干净的文件名或path…不是两个。 这是我的解决scheme:

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

在这里扫描答案,他们都**似乎涉及使用无效文件名字符的字符数组。

当然,这可能是微观优化 – 但是对于任何可能希望检查大量值为有效文件名的人的好处,值得注意的是,构build无效字符的哈希集合将带来显着更好的性能。

在过去,我一直非常惊讶(震惊),哈希集(或字典)在列表中迭代的速度有多快。 用string,这是一个可笑的低数字(从内存约5-7项)。 与其他大多数简单的数据(对象引用,数字等),魔术交叉似乎是约20项。

Path.InvalidFileNameChars“list”中有40个无效字符。 今天做了一个search,在StackOverflow中有一个相当好的基准,它显示了哈希集合需要超过40个项目的数组/列表的一半时间: https ://stackoverflow.com/a/10762995/949129

以下是我用于清理path的助手类。 我现在忘了为什么我有更换的select,但它在那里是一个可爱的奖金。

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

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

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

或者你可以做

 [YOUR STRING].Replace('\\', ' ').Replace('/', ' ').Replace('"', ' ').Replace('*', ' ').Replace(':', ' ').Replace('?', ' ').Replace('<', ' ').Replace('>', ' ').Replace('|', ' ').Trim();