Based on Andre's excellent answer but taking into account Spud's comment on reserved words, I made this version:
/// <summary> /// Strip illegal chars and reserved words from a candidate filename (should not include the directory path) /// </summary> /// <remarks> /// http://stackoverflow.com/questions/309485/c-sharp-sanitize-file-name /// </remarks> public static string CoerceValidFileName(string filename) { var invalidChars = Regex.Escape(new string(Path.GetInvalidFileNameChars())); var invalidReStr = string.Format(@"[{0}]+", invalidChars); var reservedWords = new [] { "CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; var sanitisedNamePart = Regex.Replace(filename, invalidReStr, "_"); foreach (var reservedWord in reservedWords) { var reservedWordPattern = string.Format("^{0}\\.", reservedWord); sanitisedNamePart = Regex.Replace(sanitisedNamePart, reservedWordPattern, "_reservedWord_.", RegexOptions.IgnoreCase); } return sanitisedNamePart; }
And these are my unit tests
[Test] public void CoerceValidFileName_SimpleValid() { var filename = @"thisIsValid.txt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual(filename, result); } [Test] public void CoerceValidFileName_SimpleInvalid() { var filename = @"thisIsNotValid\3\\_3.txt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual("thisIsNotValid_3__3.txt", result); } [Test] public void CoerceValidFileName_InvalidExtension() { var filename = @"thisIsNotValid.t\xt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual("thisIsNotValid.t_xt", result); } [Test] public void CoerceValidFileName_KeywordInvalid() { var filename = "aUx.txt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual("_reservedWord_.txt", result); } [Test] public void CoerceValidFileName_KeywordValid() { var filename = "auxillary.txt"; var result = PathHelper.CoerceValidFileName(filename); Assert.AreEqual("auxillary.txt", result); }