System.IO.Path.GetInvalidFileNameChars() has all the invalid characters.
Here's a sample method:
public static string SanitizeFileName ( string fileName, char replacementChar = '_' ) { HashSet<char> blocked = new(System.IO.Path.GetInvalidFileNameChars()); char[] output = fileName.ToCharArray(); for (int i = 0, ln = output.Length; i < ln; i++) { if (blocked.Contains(output[i])) { output[i] = replacementChar; } } return new String(output); }
As pointed out by pixel, this would translate
my\\\file\\\\\\\\\\name
into
my___file__________name
... which may be unattractive.
If this function is something you might call in a batch or if you'd like the flexibility to replace consecutive invalid characters with a single replacement, you may want something like this:
public class FileNameSanitizer { // cache the blocked characters private HashSet<char> _blocked = new(System.IO.Path.GetInvalidFileNameChars()); /// <summary>Replace individual invalid characters one-for-one.</summary> public string Sanitize ( string fileName, char replacementChar = '_' ) { char[] output = fileName.ToCharArray(); for (int i = 0, ln = output.Length; i < ln; i++) { if (_blocked.Contains(output[i])) { output[i] = replacementChar; } } return new String(output); } /// <summary>Replace consecutive invalid characters with a single replacement character.</summary> public string SanitizeCondensed ( string fileName, char replacementChar = '_' ) { char[] output = fileName.ToCharArray(); char current; bool replaced = false; int i = 0, x = 0, ln = output.Length; for (; i < ln; i++) { current = output[i]; if (_blocked.Contains(current)) { if (!replaced) { output[x++] = replacementChar; } replaced = true; } else { output[x++] = current; replaced = false; } } return new String(output, 0, x); } }