임의의 문자열에서 유효한 Windows 파일 이름을 만드는 방법은 무엇입니까?

StackOverflow https://stackoverflow.com/questions/620605

  •  05-07-2019
  •  | 
  •  

문제

파일 이름으로 사용하고 싶은 "foo : bar"와 같은 문자열이 있지만 Windows에서 ":"char는 파일 이름으로 허용되지 않습니다.

"foo : bar"를 "foo-bar"와 같은 것으로 바꿀 방법이 있습니까?

도움이 되었습니까?

해결책

다음과 같은 것을 시도하십시오.

string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
   fileName = fileName.Replace(c, '_');
}

편집하다:

부터 GetInvalidFileNameChars() 10 ~ 15 숯을 반환하면 사용하는 것이 좋습니다. StringBuilder 간단한 문자열 대신; 원래 버전은 더 오래 걸리고 더 많은 메모리를 소비합니다.

다른 팁

fileName = fileName.Replace(":", "-") 

그러나 ":"는 Windows의 유일한 불법 인물이 아닙니다. 또한 처리해야합니다.

/, \, :, *, ?, ", <, > and |

이들은 System.io.path.getInvalidFilenamechars ()에 포함되어 있습니다.

또한 (Windows), "." 파일 이름에서 유일한 캐릭터가 될 수는 없습니다 (둘 다 ".", "..", "..."등은 유효하지 않습니다). "."와 함께 파일을 명명 할 때주의하십시오.

echo "test" > .test.

".Test"라는 파일을 생성합니다.

마지막으로, 당신이 있다면 진짜 일을 정확하게하고 싶다면 일부가 있습니다 특수 파일 이름 당신은 찾아야합니다. 창에 이름이 지정된 파일을 만들 수 없습니다.

CON, PRN, AUX, CLOCK$, NUL
COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9
LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9.

이것은 더 효율적이지는 않지만 더 재미 있습니다 :)

    var fileName = "foo:bar";
    var invalidChars = System.IO.Path.GetInvalidFileNameChars();
    var cleanFileName = new string(fileName.Where(m => !invalidChars.Contains(m)).ToArray<char>());

누구나 최적화 된 버전을 원하는 경우 StringBuilder, 이것을 사용하십시오. 옵션으로 Rkagerer의 트릭을 포함합니다.

static char[] _invalids;

/// <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 simply remove bad characters.</param>
/// <param name="fancy">Whether 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, returns "_".</returns>
public static string MakeValidFileName(string text, char? replacement = '_', bool fancy = true)
{
    StringBuilder sb = new StringBuilder(text.Length);
    var invalids = _invalids ?? (_invalids = Path.GetInvalidFileNameChars());
    bool changed = false;
    for (int i = 0; i < text.Length; i++) {
        char c = text[i];
        if (invalids.Contains(c)) {
            changed = true;
            var repl = replacement ?? '\0';
            if (fancy) {
                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;
}

Diego는 올바른 솔루션을 가지고 있지만 거기에는 매우 작은 실수가 있습니다. String.replace의 버전은 string.replace (char, char)이어야합니다. String.replace (char, string)가 없습니다.

답을 편집 할 수 없거나 방금 사소한 변화를 일으켰을 것입니다.

그래서 그것은 다음과 같아야합니다.

string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
   fileName = fileName.Replace(c, '_');
}

Diego의 답변에 약간의 비틀림이 있습니다.

유니 코드를 두려워하지 않으면 유효하지 않은 문자를 유효한 유효한 유니 코드 기호로 바꾸어 조금 더 충실도를 유지할 수 있습니다. 다음은 Lumber Cutlist와 관련된 최근 프로젝트에서 사용한 코드입니다.

static string MakeValidFilename(string text) {
  text = text.Replace('\'', '’'); // U+2019 right single quotation mark
  text = text.Replace('"',  '”'); // U+201D right double quotation mark
  text = text.Replace('/', '⁄');  // U+2044 fraction slash
  foreach (char c in System.IO.Path.GetInvalidFileNameChars()) {
    text = text.Replace(c, '_');
  }
  return text;
}

이것은 같은 파일 이름을 생성합니다 1⁄2” spruce.txt 대신에 1_2_ spruce.txt

예, 실제로 작동합니다.

Explorer sample

경고 emptor

나는이 트릭이 NTF에서 작동한다는 것을 알았지 만 지방과 FAT32 파티션에서도 작동한다는 사실에 놀랐습니다. 그것은 ~ 때문에 긴 파일 이름 ~이다 유니 코드에 저장됩니다, 조차 뒤로 Windows 95/nt로 나는 Win7, XP, 심지어 Linux 기반 라우터를 테스트했는데 그들은 괜찮습니다. DOSBOX 내부에서도 똑같이 말할 수 없습니다.

즉, 당신이 이것에 미치기 전에, 당신이 실제로 추가 충실도가 필요한지 고려하십시오. 유니 코드 룩-알리 크는 사람들이나 오래된 프로그램을 혼란스럽게 할 수 있습니다. 코드.

다음은 허용 된 답변의 버전입니다 Linq 사용하는 Enumerable.Aggregate:

string fileName = "something";

Path.GetInvalidFileNameChars()
    .Aggregate(fileName, (current, c) => current.Replace(c, '_'));

다음은 사용하는 버전입니다 StringBuilder 그리고 IndexOfAny 전체 효율성에 대한 대량 추가. 또한 중복 문자열을 만들지 않고 원래 문자열을 반환합니다.

마지막으로, 원하는 방식으로 사용자 정의 할 수있는 모양과 같은 문자를 반환하는 스위치 문이 있습니다. 체크 아웃 unicode.org의 혼란스러운 조회 글꼴에 따라 어떤 옵션을 가질 수 있는지 확인합니다.

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

확인하지 않습니다 ., .., 또는 예약 된 이름과 같은 이름 CON 교체가 무엇인지 명확하지 않기 때문입니다.

또 다른 간단한 해결책 :

private string MakeValidFileName(string original, char replacementChar = '_')
{
  var invalidChars = new HashSet<char>(Path.GetInvalidFileNameChars());
  return new string(original.Select(c => invalidChars.Contains(c) ? replacementChar : c).ToArray());
}

코드를 약간 정리하고 약간의 리팩토링을 만들기 ... 문자열 유형에 대한 확장자를 만들었습니다.

public static string ToValidFileName(this string s, char replaceChar = '_', char[] includeChars = null)
{
  var invalid = Path.GetInvalidFileNameChars();
  if (includeChars != null) invalid = invalid.Union(includeChars).ToArray();
  return string.Join(string.Empty, s.ToCharArray().Select(o => o.In(invalid) ? replaceChar : o));
}

이제 사용하기가 더 쉽습니다.

var name = "Any string you want using ? / \ or even +.zip";
var validFileName = name.ToValidFileName();

"_"와 다른 숯으로 교체하려면 다음을 사용할 수 있습니다.

var validFileName = name.ToValidFileName(replaceChar:'#');

교체 할 숯을 추가 할 수 있습니다. 예를 들어 공백이나 쉼표를 원하지 않습니다.

var validFileName = name.ToValidFileName(includeChars: new [] { ' ', ',' });

도움이되기를 바랍니다 ...

건배

오늘이 작업을 수행해야했습니다. 제 경우에는 최종 .kmz 파일의 날짜 및 시간과 고객 이름을 연결해야했습니다. 나의 최종 해결책은 이것입니다.

 string name = "Whatever name with valid/invalid chars";
 char[] invalid = System.IO.Path.GetInvalidFileNameChars();
 string validFileName = string.Join(string.Empty,
                            string.Format("{0}.{1:G}.kmz", name, DateTime.Now)
                            .ToCharArray().Select(o => o.In(invalid) ? '_' : o));

공간 숯을 유효하지 않은 배열에 추가하면 공백을 교체 할 수도 있습니다.

어쩌면 가장 빠르지는 않지만 성능이 문제가되지 않았기 때문에 우아하고 이해할 수 있음을 알았습니다.

건배!

당신은 이것을 a로 할 수 있습니다 sed 명령:

 sed -e "
 s/[?()\[\]=+<>:;©®”,*|]/_/g
 s/"$'\t'"/ /g
 s/–/-/g
 s/\"/_/g
 s/[[:cntrl:]]/_/g"
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top