파일 이름으로 사용하려는 "Foo : Bar"와 같은 문자열이 있지만 Windows에서는 파일 이름에 ":"문자를 사용할 수 없습니다.
"Foo : Bar"를 "Foo- Bar"와 같은 것으로 바꾸는 방법이 있습니까?
답변:
다음과 같이 시도하십시오.
string fileName = "something";
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
fileName = fileName.Replace(c, '_');
}
편집하다:
GetInvalidFileNameChars()
10 개 또는 15 개의 문자를 반환 하므로 StringBuilder
간단한 문자열 대신 a를 사용하는 것이 좋습니다. 원래 버전은 더 오래 걸리고 더 많은 메모리를 소비합니다.
file.name.txt.pdf
유효한 pdf입니다. Windows .
는 확장에 대해 마지막 만 읽습니다 .
fileName = fileName.Replace(":", "-")
그러나 ":"는 Windows에서 유일한 잘못된 문자가 아닙니다. 또한 다음을 처리해야합니다.
/, \, :, *, ?, ", <, > and |
이들은 System.IO.Path.GetInvalidFileNameChars ();에 포함되어 있습니다.
또한 (Windows에서는) "." 파일 이름에서 유일한 문자가 될 수 없습니다 ( ".", "..", "..."등 모두 유효하지 않음). "."로 파일 이름을 지정할 때주의하십시오. 예를 들면 다음과 같습니다.
echo "test" > .test.
".test"라는 파일을 생성합니다.
마지막으로, 정말로 제대로하고 싶다면 찾아봐야 할 특별한 파일 이름이 있습니다. Windows에서는 다음과 같은 파일을 만들 수 없습니다.
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.
을 기반으로 최적화 된 버전을 원하는 사람이 있으면 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;
}
다음을 사용 Linq
하는 허용되는 답변의 버전은 다음과 같습니다 Enumerable.Aggregate
.
string fileName = "something";
Path.GetInvalidFileNameChars()
.Aggregate(fileName, (current, c) => current.Replace(c, '_'));
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의 대답에 약간의 비틀기가 있습니다.
유니 코드를 두려워하지 않는 경우 유효하지 않은 문자를 유사한 유효한 유니 코드 기호로 대체하여 좀 더 충실도를 유지할 수 있습니다. 다음은 목재 절단 목록과 관련된 최근 프로젝트에서 사용한 코드입니다.
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
예, 실제로 작동합니다.
경고 Emptor
이 트릭이 NTFS에서 작동한다는 것을 알고 있었지만 FAT 및 FAT32 파티션에서도 작동한다는 사실에 놀랐습니다. 때문에의 그 긴 파일 이름이 되는 유니 코드로 저장 심지어 까지 다시 윈도우 95 / NT 등. 나는 Win7, XP, 심지어 Linux 기반 라우터에서도 테스트를했는데 괜찮았다. DOSBox 내부에서도 똑같이 말할 수 없습니다.
즉, 당신이 이것에 열광하기 전에 추가 충실도가 정말로 필요한지 고려하십시오. 유니 코드와 유사한 모양은 사람이나 오래된 프로그램을 혼동 할 수 있습니다. 예를 들어 코드 페이지에 의존하는 오래된 OS가 있습니다.
여기 버전의 사용 StringBuilder
및 IndexOfAny
전체 효율을 대량 APPEND와. 또한 중복 문자열을 생성하는 대신 원래 문자열을 반환합니다.
마지막으로, 원하는 방식으로 사용자 정의 할 수있는 유사 문자를 반환하는 switch 문이 있습니다. 체크 아웃 Unicode.org의 confusables가 조회 글꼴에 따라, 당신이있을 어떤 옵션을 볼 수 있습니다.
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
이 삭제되지 않기 때문에이 교체 될해야하는지.
약간의 코드를 정리하고 약간의 리팩토링을 ... 문자열 유형에 대한 확장을 만들었습니다.
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 [] { ' ', ',' });
도움이 되길 바랍니다 ...
건배
또 다른 간단한 해결책 :
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 class Extension
{
/// <summary>
/// Characters allowed in a file name. Note that curly braces don't show up here
/// becausee they are used for escaping invalid characters.
/// </summary>
private static readonly HashSet<char> CleanFileNameChars = new HashSet<char>
{
' ', '!', '#', '$', '%', '&', '\'', '(', ')', '+', ',', '-', '.',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '=', '@',
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
'[', ']', '^', '_', '`',
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
};
/// <summary>
/// Creates a clean file name from one that may contain invalid characters in
/// a way that will not collide.
/// </summary>
/// <param name="dirtyFileName">
/// The file name that may contain invalid filename characters.
/// </param>
/// <returns>
/// A file name that does not contain invalid filename characters.
/// </returns>
/// <remarks>
/// <para>
/// Escapes invalid characters by converting their ASCII values to hexadecimal
/// and wrapping that value in curly braces. Curly braces are escaped by doubling
/// them, for example '{' => "{{".
/// </para>
/// <para>
/// Note that although NTFS allows unicode characters in file names, this
/// method does not.
/// </para>
/// </remarks>
public static string CleanFileName(this string dirtyFileName)
{
string EscapeHexString(char c) =>
"{" + (c > 255 ? $"{(uint)c:X4}" : $"{(uint)c:X2}") + "}";
return string.Join(string.Empty,
dirtyFileName.Select(
c =>
c == '{' ? "{{" :
c == '}' ? "}}" :
CleanFileNameChars.Contains(c) ? $"{c}" :
EscapeHexString(c)));
}
}
오늘이 작업을 수행해야했습니다 ... 제 경우에는 최종 .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));
유효하지 않은 배열에 공백 문자를 추가하면 공백을 대체 할 수도 있습니다.
가장 빠르지는 않지만 성능이 문제가되지 않았기 때문에 우아하고 이해하기 쉬웠습니다.
건배!
다음 sed
명령으로 이를 수행 할 수 있습니다 .
sed -e "
s/[?()\[\]=+<>:;©®”,*|]/_/g
s/"$'\t'"/ /g
s/–/-/g
s/\"/_/g
s/[[:cntrl:]]/_/g"