임의의 문자열에서 유효한 Windows 파일 이름을 만드는 방법은 무엇입니까?
파일 이름으로 사용하려는 "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를 사용하는 것이 좋습니다. 원래 버전은 더 오래 걸리고 더 많은 메모리를 소비합니다.
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.
이것은 더 효율적이지는 않지만 더 재미 있습니다. :)
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의 대답에 약간의 비틀기가 있습니다.
유니 코드를 두려워하지 않는 경우 유효하지 않은 문자를 유사한 유효한 유니 코드 기호로 대체하여 좀 더 충실도를 유지할 수 있습니다. 다음은 목재 절단 목록과 관련된 최근 프로젝트에서 사용한 코드입니다.
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가 있습니다.
다음을 사용 Linq
하는 허용되는 답변 버전은 다음과 같습니다 Enumerable.Aggregate
.
string fileName = "something";
Path.GetInvalidFileNameChars()
.Aggregate(fileName, (current, c) => current.Replace(c, '_'));
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.
Cleaning a little my code and making a little refactoring... I created an extension for string type:
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));
}
Now it's easier to use with:
var name = "Any string you want using ? / \ or even +.zip";
var validFileName = name.ToValidFileName();
If you want to replace with a different char than "_" you can use:
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());
}
오늘이 작업을 수행해야했습니다. 제 경우에는 고객 이름을 최종 .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));
유효하지 않은 배열에 공백 문자를 추가하면 공백을 대체 할 수도 있습니다.
가장 빠르지는 않지만 성능이 문제가되지 않았기 때문에 우아하고 이해하기 쉬웠습니다.
건배!
충돌을 만들 수없는 시스템이 필요했기 때문에 여러 캐릭터를 하나로 매핑 할 수 없었습니다. 나는 결국 :
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)));
}
}
다음 sed
명령으로 이를 수행 할 수 있습니다 .
sed -e "
s/[?()\[\]=+<>:;©®”,*|]/_/g
s/"$'\t'"/ /g
s/–/-/g
s/\"/_/g
s/[[:cntrl:]]/_/g"
'Programing' 카테고리의 다른 글
htaccess로 디렉토리 목록 거부 (0) | 2020.09.18 |
---|---|
Rails 콘솔에서 FactoryGirl의 팩토리를 사용하는 방법 (0) | 2020.09.18 |
Oracle 데이터베이스에서 임시 테이블을 어떻게 생성합니까? (0) | 2020.09.18 |
목록을 "올바르게"인쇄하는 방법은 무엇입니까? (0) | 2020.09.18 |
한 SQL Server 테이블에서 다른 테이블로 행을 복사하는 방법 (0) | 2020.09.18 |