How to make a valid Windows filename from an arbitrary string?

后端 未结 14 1071
伪装坚强ぢ
伪装坚强ぢ 2020-12-23 02:50

I\'ve got a string like \"Foo: Bar\" that I want to use as a filename, but on Windows the \":\" char isn\'t allowed in a filename.

Is there a method that will turn \

14条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-23 03:32

    Here's a version that uses StringBuilder and IndexOfAny with bulk append for full efficiency. It also returns the original string rather than create a duplicate string.

    Last but not least, it has a switch statement that returns look-alike characters which you can customize any way you wish. Check out Unicode.org's confusables lookup to see what options you might have, depending on the font.

    public static string GetSafeFilename(string arbitraryString)
    {
        var invalidChars = System.IO.Path.GetInvalidFileNameChars();
        var replaceIndex = arbitraryString.IndexOfAny(invalidChars, 0);
        if (replaceIndex == -1) return arbitraryString;
    
        var r = new StringBuilder();
        var i = 0;
    
        do
        {
            r.Append(arbitraryString, i, replaceIndex - i);
    
            switch (arbitraryString[replaceIndex])
            {
                case '"':
                    r.Append("''");
                    break;
                case '<':
                    r.Append('\u02c2'); // '˂' (modifier letter left arrowhead)
                    break;
                case '>':
                    r.Append('\u02c3'); // '˃' (modifier letter right arrowhead)
                    break;
                case '|':
                    r.Append('\u2223'); // '∣' (divides)
                    break;
                case ':':
                    r.Append('-');
                    break;
                case '*':
                    r.Append('\u2217'); // '∗' (asterisk operator)
                    break;
                case '\\':
                case '/':
                    r.Append('\u2044'); // '⁄' (fraction slash)
                    break;
                case '\0':
                case '\f':
                case '?':
                    break;
                case '\t':
                case '\n':
                case '\r':
                case '\v':
                    r.Append(' ');
                    break;
                default:
                    r.Append('_');
                    break;
            }
    
            i = replaceIndex + 1;
            replaceIndex = arbitraryString.IndexOfAny(invalidChars, i);
        } while (replaceIndex != -1);
    
        r.Append(arbitraryString, i, arbitraryString.Length - i);
    
        return r.ToString();
    }
    

    It doesn't check for ., .., or reserved names like CON because it isn't clear what the replacement should be.

提交回复
热议问题