내 프로그램은 인터넷에서 임의의 문자열을 가져 와서 파일 이름으로 사용합니다. 이러한 문자열에서 잘못된 문자를 제거하는 간단한 방법이 있습니까? 아니면 이에 대한 사용자 지정 함수를 작성해야합니까?
답변:
어, 사람들이 어떤 문자가 유효한지 추측하려고 할 때 싫어요. 완전히 이식 할 수없는 것 외에도 (항상 Mono에 대해 생각 함) 이전 주석 모두 25 개 이상의 유효하지 않은 문자를 놓쳤습니다.
'Clean just a filename
Dim filename As String = "salmnas dlajhdla kjha;dmas'lkasn"
For Each c In IO.Path.GetInvalidFileNameChars
filename = filename.Replace(c, "")
Next
'See also IO.Path.GetInvalidPathChars
유효하지 않은 문자를 제거하려면 :
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars
var validFilename = new string(filename.Where(ch => !invalidFileNameChars.Contains(ch)).ToArray());
유효하지 않은 문자를 바꾸려면 :
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars and an _ for invalid ones
var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? '_' : ch).ToArray());
유효하지 않은 문자를 바꾸려면 (그리고 Hell * vs Hell $와 같은 잠재적 인 이름 충돌을 방지) :
static readonly IList<char> invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars and replaces invalid chars with a unique letter (Moves the Char into the letter range of unicode, starting at "A")
var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? Convert.ToChar(invalidFileNameChars.IndexOf(ch) + 65) : ch).ToArray());
이 질문은 이전에 여러 번 요청되었으며 이전에 여러 번 지적했듯이 IO.Path.GetInvalidFileNameChars
적절하지 않습니다.
첫째, PRN 및 CON과 같이 예약되어 있고 파일 이름에 허용되지 않는 이름이 많이 있습니다. 루트 폴더에만 허용되지 않는 다른 이름이 있습니다. 마침표로 끝나는 이름도 허용되지 않습니다.
둘째, 다양한 길이 제한이 있습니다. 여기 에서 NTFS에 대한 전체 목록을 읽어보십시오 .
셋째, 다른 제한이있는 파일 시스템에 연결할 수 있습니다. 예를 들어 ISO 9660 파일 이름은 "-"로 시작할 수 없지만 포함 할 수 있습니다.
넷째, 두 프로세스가 "임의로"같은 이름을 선택하면 어떻게합니까?
일반적으로 파일 이름에 대해 외부에서 생성 된 이름을 사용하는 것은 좋지 않습니다. 자신의 개인 파일 이름을 생성하고 사람이 읽을 수있는 이름을 내부적으로 저장하는 것이 좋습니다.
나는 Grauenwolf에 동의하며 Path.GetInvalidFileNameChars()
내 C # 기여는 다음과 같습니다.
string file = @"38?/.\}[+=n a882 a.a*/|n^%$ ad#(-))";
Array.ForEach(Path.GetInvalidFileNameChars(),
c => file = file.Replace(c.ToString(), String.Empty));
추신-이건 당연한 것보다 더 은밀합니다-저는 간결하게하려고했습니다.
Array.ForEach
단지 대신 foreach
여기
Path.GetInvalidFileNameChars().Aggregate(file, (current, c) => current.Replace(c, '-'))
내 버전은 다음과 같습니다.
static string GetSafeFileName(string name, char replace = '_') {
char[] invalids = Path.GetInvalidFileNameChars();
return new string(name.Select(c => invalids.Contains(c) ? replace : c).ToArray());
}
GetInvalidFileNameChars의 결과가 어떻게 계산되는지 잘 모르겠지만 "Get"은 그것이 사소하지 않다고 제안하므로 결과를 캐시합니다. 또한 이것은 잘못된 문자 집합을 반복하는 위의 솔루션과 같이 여러 번 대신 한 번만 입력 문자열을 탐색하여 소스 문자열에서 한 번에 하나씩 대체합니다. 또한 Where 기반 솔루션을 좋아하지만 유효하지 않은 문자를 제거하는 대신 대체하는 것을 선호합니다. 마지막으로, 문자열을 반복 할 때 문자를 문자열로 변환하지 않도록 정확히 한 문자를 대체합니다.
나는 프로파일 링을하지 않고 모든 것을 말한다. 이것은 나에게 단지 "느낌"이었다. :)
new HashSet<char>(Path.GetInvalidFileNameChars())
O (n) 열거 (미세 최적화)를 피할 수 있습니다.
파일 이름에 대해 사용자가 더 쉽게 읽을 수있는 모든 특수 문자를 신속하게 제거하려면 다음과 같이 잘 작동합니다.
string myCrazyName = "q`w^e!r@t#y$u%i^o&p*a(s)d_f-g+h=j{k}l|z:x\"c<v>b?n[m]q\\w;e'r,t.y/u";
string safeName = Regex.Replace(
myCrazyName,
"\W", /*Matches any nonword character. Equivalent to '[^A-Za-z0-9_]'*/
"",
RegexOptions.IgnoreCase);
// safeName == "qwertyuiopasd_fghjklzxcvbnmqwertyu"
\W
는 알파벳이 아닌 숫자 ( [^A-Za-z0-9_]
) 보다 더 많이 일치 합니다. 모든 유니 코드 '단어'문자 (русский 中文 ... 등)도 대체되지 않습니다. 그러나 이것은 좋은 것입니다.
.
되므로 먼저 확장을 추출하고 나중에 다시 추가해야한다는 것입니다.
문자열을 다음과 같이 Base64로 변환하지 않는 이유는 무엇입니까?
string UnsafeFileName = "salmnas dlajhdla kjha;dmas'lkasn";
string SafeFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(UnsafeFileName));
읽을 수 있도록 다시 변환하려면 :
UnsafeFileName = Encoding.UTF8.GetString(Convert.FromBase64String(SafeFileName));
무작위 설명에서 고유 한 이름으로 PNG 파일을 저장하는 데 사용했습니다.
위의 Dour High Arch가 게시 한 관련 스택 오버플로 질문에 대한 링크에서 수집 한 정보를 기반으로 ClipFlair의 ( http://github.com/Zoomicon/ClipFlair ) StringExtensions 정적 클래스 (Utils.Silverlight 프로젝트)에 방금 추가 한 내용은 다음과 같습니다 .
public static string ReplaceInvalidFileNameChars(this string s, string replacement = "")
{
return Regex.Replace(s,
"[" + Regex.Escape(new String(System.IO.Path.GetInvalidPathChars())) + "]",
replacement, //can even use a replacement string of any length
RegexOptions.IgnoreCase);
//not using System.IO.Path.InvalidPathChars (deprecated insecure API)
}
private void textBoxFileName_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = CheckFileNameSafeCharacters(e);
}
/// <summary>
/// This is a good function for making sure that a user who is naming a file uses proper characters
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
internal static bool CheckFileNameSafeCharacters(System.Windows.Forms.KeyPressEventArgs e)
{
if (e.KeyChar.Equals(24) ||
e.KeyChar.Equals(3) ||
e.KeyChar.Equals(22) ||
e.KeyChar.Equals(26) ||
e.KeyChar.Equals(25))//Control-X, C, V, Z and Y
return false;
if (e.KeyChar.Equals('\b'))//backspace
return false;
char[] charArray = Path.GetInvalidFileNameChars();
if (charArray.Contains(e.KeyChar))
return true;//Stop the character from being entered into the control since it is non-numerical
else
return false;
}
많은 사람들 Path.GetInvalidFileNameChars()
이 나에게 나쁜 해결책처럼 보이는 사용 을 제안합니다 . 해커는 항상이를 우회 할 방법을 찾기 때문에 블랙리스트 대신 화이트리스트를 사용하는 것이 좋습니다.
다음은 사용할 수있는 코드의 예입니다.
string whitelist = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.";
foreach (char c in filename)
{
if (!whitelist.Contains(c))
{
filename = filename.Replace(c, '-');
}
}