경로와 파일 이름에서 잘못된 문자를 제거하는 방법은 무엇입니까?
간단한 문자열에서 잘못된 경로와 파일 문자를 제거하는 강력하고 간단한 방법이 필요합니다. 아래 코드를 사용했지만 아무것도하지 않는 것 같습니다. 무엇이 누락 되었습니까?
using System;
using System.IO;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
string illegal = "\"M<>\"\\a/ry/ h**ad:>> a\\/:*?\"<>| li*tt|le|| la\"mb.?";
illegal = illegal.Trim(Path.GetInvalidFileNameChars());
illegal = illegal.Trim(Path.GetInvalidPathChars());
Console.WriteLine(illegal);
Console.ReadLine();
}
}
}
대신 이와 같은 것을 시도하십시오.
string illegal = "\"M\"\\a/ry/ h**ad:>> a\\/:*?\"| li*tt|le|| la\"mb.?";
string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
foreach (char c in invalid)
{
illegal = illegal.Replace(c.ToString(), "");
}
그러나 나는 의견에 동의해야합니다. 나는 불법 경로를 합법적이지만 의도하지 않은 경로로 엉망으로 만들기보다는 불법 경로의 출처를 다루려고 노력할 것입니다.
편집 : 또는 Regex를 사용하여 잠재적으로 '더 나은'솔루션.
string illegal = "\"M\"\\a/ry/ h**ad:>> a\\/:*?\"| li*tt|le|| la\"mb.?";
string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch)));
illegal = r.Replace(illegal, "");
아직도, 질문은 구걸, 왜 당신이 처음에 이것을하고 있는지.
원래 질문은 "잘못된 문자 제거"를 요청했습니다.
public string RemoveInvalidChars(string filename)
{
return string.Concat(filename.Split(Path.GetInvalidFileNameChars()));
}
대신 그것들을 바꾸고 싶을 수도 있습니다.
public string ReplaceInvalidChars(string filename)
{
return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));
}
이 답변은 Ceres의 또 다른 스레드에 있었으며 정말 깔끔하고 간단합니다.
Linq를 사용하여 파일 이름을 정리합니다. 유효한 경로를 확인하기 위해이를 쉽게 확장 할 수 있습니다.
private static string CleanFileName(string fileName)
{
return Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty));
}
최신 정보
일부 의견은이 방법이 작동하지 않는다고 표시하므로 DotNetFiddle 코드 조각에 대한 링크를 포함하여 방법을 확인할 수 있습니다.
https://dotnetfiddle.net/nw1SWY
Linq를 사용하여 다음과 같이 잘못된 문자를 제거 할 수 있습니다.
var invalidChars = Path.GetInvalidFileNameChars();
var invalidCharsRemoved = stringWithInvalidChars
.Where(x => !invalidChars.Contains(x))
.ToArray();
편집
주석에 언급 된 필수 편집으로 표시되는 방식입니다.
var invalidChars = Path.GetInvalidFileNameChars();
string invalidCharsRemoved = new string(stringWithInvalidChars
.Where(x => !invalidChars.Contains(x))
.ToArray());
이것들은 모두 훌륭한 솔루션이지만 모두 Path.GetInvalidFileNameChars
신뢰할 수있는 것입니다. MSDN 설명서에서 Path.GetInvalidFileNameChars
다음 내용 을 확인하십시오 .
이 메소드에서 리턴 된 배열 은 파일 및 디렉토리 이름에 유효하지 않은 전체 문자 세트를 포함하지 않을 수 있습니다. 유효하지 않은 문자의 전체 세트는 파일 시스템에 따라 다를 수 있습니다. 예를 들어, Windows 기반 데스크탑 플랫폼에서 유효하지 않은 경로 문자에는 ASCII / 유니 코드 문자 1-31뿐만 아니라 따옴표 ( "),보다 작음 (<),보다 큼 (>), 파이프 (|), 백 스페이스 ( \ b), null (\ 0) 및 탭 (\ t)입니다.
Path.GetInvalidPathChars
방법으로는 나아지지 않습니다 . 똑같은 말이 포함되어 있습니다.
파일 이름의 경우 :
string cleanFileName = String.Join("", fileName.Split(Path.GetInvalidFileNameChars()));
전체 경로 :
string cleanPath = String.Join("", path.Split(Path.GetInvalidPathChars()));
이 기능을 보안 기능으로 사용하려는 경우보다 강력한 방법은 모든 경로를 확장 한 다음 사용자 제공 경로가 사용자가 액세스 할 수있는 디렉토리의 하위 항목인지 확인하는 것입니다.
우선 Trim은 문자열의 시작 또는 끝에서 문자 만 제거합니다 . 두 번째로, 공격적인 문자를 실제로 제거 할 것인지 평가하거나 빠르게 실패하여 파일 이름이 잘못되었음을 사용자에게 알려야합니다. 나의 선택은 후자이지만, 나의 대답은 최소한 옳고 그른 방법으로 일을하는 방법을 보여 주어야합니다
주어진 문자열이 유효한 파일 이름인지 확인하는 방법을 보여주는 StackOverflow 질문 . 이 질문에서 정규 표현식을 사용하여 정규 표현식 대체 문자를 제거 할 수 있습니다 (실제로이 작업을 수행 해야하는 경우).
나는 이것을 달성하기 위해 정규 표현식을 사용합니다. 먼저 정규식을 동적으로 작성합니다.
string regex = string.Format(
"[{0}]",
Regex.Escape(new string(Path.GetInvalidFileNameChars())));
Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);
그런 다음 removeInvalidChars.Replace를 호출하여 찾기 및 바꾸기를 수행합니다. 이것은 경로 문자를 포함하도록 분명히 확장 될 수 있습니다.
사용자 입력에서 잘못된 문자를 제거하는 가장 좋은 방법은 Regex 클래스를 사용하여 잘못된 문자를 바꾸거나 코드 숨김 메소드를 작성하거나 RegularExpression 제어를 사용하여 클라이언트 측에서 유효성을 검증하는 것입니다.
public string RemoveSpecialCharacters(string str)
{
return Regex.Replace(str, "[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled);
}
또는
<asp:RegularExpressionValidator ID="regxFolderName"
runat="server"
ErrorMessage="Enter folder name with a-z A-Z0-9_"
ControlToValidate="txtFolderName"
Display="Dynamic"
ValidationExpression="^[a-zA-Z0-9_]*$"
ForeColor="Red">
나는 Jeff Yates의 아이디어를 절대적으로 선호합니다. 약간 수정하면 완벽하게 작동합니다.
string regex = String.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars())));
Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);
개선 된 기능은 자동으로 생성 된 정규식을 피하는 것입니다.
다음은 .NET 3 이상에 도움이되는 코드 스 니펫입니다.
using System.IO;
using System.Text.RegularExpressions;
public static class PathValidation
{
private static string pathValidatorExpression = "^[^" + string.Join("", Array.ConvertAll(Path.GetInvalidPathChars(), x => Regex.Escape(x.ToString()))) + "]+$";
private static Regex pathValidator = new Regex(pathValidatorExpression, RegexOptions.Compiled);
private static string fileNameValidatorExpression = "^[^" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]+$";
private static Regex fileNameValidator = new Regex(fileNameValidatorExpression, RegexOptions.Compiled);
private static string pathCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidPathChars(), x => Regex.Escape(x.ToString()))) + "]";
private static Regex pathCleaner = new Regex(pathCleanerExpression, RegexOptions.Compiled);
private static string fileNameCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]";
private static Regex fileNameCleaner = new Regex(fileNameCleanerExpression, RegexOptions.Compiled);
public static bool ValidatePath(string path)
{
return pathValidator.IsMatch(path);
}
public static bool ValidateFileName(string fileName)
{
return fileNameValidator.IsMatch(fileName);
}
public static string CleanPath(string path)
{
return pathCleaner.Replace(path, "");
}
public static string CleanFileName(string fileName)
{
return fileNameCleaner.Replace(fileName, "");
}
}
위의 대부분의 솔루션은 경로와 파일 이름 모두에 잘못된 문자를 결합합니다 (두 호출이 현재 동일한 문자 집합을 반환하더라도). 먼저 경로와 파일 이름에서 경로 + 파일 이름을 분할 한 다음 적절한 세트를 적용하고 둘을 다시 결합하십시오.
wvd_vegt
유효하지 않은 문자를 단일 문자로 제거하거나 바꾸면 충돌이 발생할 수 있습니다.
<abc -> abc
>abc -> abc
이것을 피하는 간단한 방법은 다음과 같습니다.
public static string ReplaceInvalidFileNameChars(string s)
{
char[] invalidFileNameChars = System.IO.Path.GetInvalidFileNameChars();
foreach (char c in invalidFileNameChars)
s = s.Replace(c.ToString(), "[" + Array.IndexOf(invalidFileNameChars, c) + "]");
return s;
}
결과:
<abc -> [1]abc
>abc -> [2]abc
예외를 던지십시오.
if ( fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 )
{
throw new ArgumentException();
}
나는이 괴물을 재미있게 썼다.
public static class FileUtility
{
private const char PrefixChar = '%';
private static readonly int MaxLength;
private static readonly Dictionary<char,char[]> Illegals;
static FileUtility()
{
List<char> illegal = new List<char> { PrefixChar };
illegal.AddRange(Path.GetInvalidFileNameChars());
MaxLength = illegal.Select(x => ((int)x).ToString().Length).Max();
Illegals = illegal.ToDictionary(x => x, x => ((int)x).ToString("D" + MaxLength).ToCharArray());
}
public static string FilenameEncode(string s)
{
var builder = new StringBuilder();
char[] replacement;
using (var reader = new StringReader(s))
{
while (true)
{
int read = reader.Read();
if (read == -1)
break;
char c = (char)read;
if(Illegals.TryGetValue(c,out replacement))
{
builder.Append(PrefixChar);
builder.Append(replacement);
}
else
{
builder.Append(c);
}
}
}
return builder.ToString();
}
public static string FilenameDecode(string s)
{
var builder = new StringBuilder();
char[] buffer = new char[MaxLength];
using (var reader = new StringReader(s))
{
while (true)
{
int read = reader.Read();
if (read == -1)
break;
char c = (char)read;
if (c == PrefixChar)
{
reader.Read(buffer, 0, MaxLength);
var encoded =(char) ParseCharArray(buffer);
builder.Append(encoded);
}
else
{
builder.Append(c);
}
}
}
return builder.ToString();
}
public static int ParseCharArray(char[] buffer)
{
int result = 0;
foreach (char t in buffer)
{
int digit = t - '0';
if ((digit < 0) || (digit > 9))
{
throw new ArgumentException("Input string was not in the correct format");
}
result *= 10;
result += digit;
}
return result;
}
}
모든 나쁜 문자를 확인하는 대신 정규식을 사용하고 허용되는 문자를 지정하는 것이 훨씬 쉽다고 생각합니다. 다음 링크를 참조하십시오. http://www.c-sharpcorner.com/UploadFile/prasad_1/RegExpPSD12062005021717AM/RegExpPSD.aspx http://www.windowsdevcenter.com/pub/a/oreilly/windows/news/csharp_0101.html
또한 "정규 표현식 편집기"를 검색하면 많은 도움이됩니다. C #으로 코드를 출력하는 곳도 있습니다.
여기서 답변을 스캔하면 모두 유효하지 않은 파일 이름 문자의 문자 배열을 사용하는 것 같습니다.
물론 이것은 미세 최적화 일 수 있지만 유효한 파일 이름으로 많은 수의 값을 확인하려는 사람들의 이익을 위해 유효하지 않은 문자의 해시 세트를 작성하면 성능이 크게 향상된다는 점에 주목할 가치가 있습니다.
나는 과거에 해시 세트 (또는 사전)가 얼마나 빨리 목록을 반복하는 것보다 우수한지 놀랐습니다. 문자열을 사용하면 엄청나게 낮은 숫자입니다 (메모리에서 약 5-7 항목). 대부분의 다른 간단한 데이터 (객체 참조, 숫자 등)에서 매직 크로스 오버는 약 20 개 항목 인 것 같습니다.
Path.InvalidFileNameChars "list"에 40 개의 유효하지 않은 문자가 있습니다. 오늘 검색을 해보니 StackOverflow에 대한 훌륭한 벤치 마크가 있습니다. 해시 세트가 40 개 항목에 대한 배열 / 목록 시간의 절반 이상을 차지한다는 것을 보여줍니다 : https : //.com/a/10762995/949129
경로를 위생 처리하는 데 사용하는 도우미 클래스는 다음과 같습니다. 멋진 교체 옵션이있는 이유를 잊어 버렸지 만 귀여운 보너스가 있습니다.
추가 보너스 방법 "IsValidLocalPath":)
(** 정규식을 사용하지 않는 것)
public static class PathExtensions
{
private static HashSet<char> _invalidFilenameChars;
private static HashSet<char> InvalidFilenameChars
{
get { return _invalidFilenameChars ?? (_invalidFilenameChars = new HashSet<char>(Path.GetInvalidFileNameChars())); }
}
/// <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 remove bad characters.</param>
/// <param name="fancyReplacements">TRUE 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, "_" is returned.</returns>
public static string ToValidFilename(this string text, char? replacement = '_', bool fancyReplacements = false)
{
StringBuilder sb = new StringBuilder(text.Length);
HashSet<char> invalids = InvalidFilenameChars;
bool changed = false;
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (invalids.Contains(c))
{
changed = true;
char repl = replacement ?? '\0';
if (fancyReplacements)
{
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;
}
/// <summary>
/// Returns TRUE if the specified path is a valid, local filesystem path.
/// </summary>
/// <param name="pathString"></param>
/// <returns></returns>
public static bool IsValidLocalPath(this string pathString)
{
// From solution at https://stackoverflow.com/a/11636052/949129
Uri pathUri;
Boolean isValidUri = Uri.TryCreate(pathString, UriKind.Absolute, out pathUri);
return isValidUri && pathUri != null && pathUri.IsLoopback;
}
}
이것은 O (n) 인 것처럼 보이고 문자열에 너무 많은 메모리를 소비하지 않습니다.
private static readonly HashSet<char> invalidFileNameChars = new HashSet<char>(Path.GetInvalidFileNameChars());
public static string RemoveInvalidFileNameChars(string name)
{
if (!name.Any(c => invalidFileNameChars.Contains(c))) {
return name;
}
return new string(name.Where(c => !invalidFileNameChars.Contains(c)).ToArray());
}
public static class StringExtensions
{
public static string RemoveUnnecessary(this string source)
{
string result = string.Empty;
string regex = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
Regex reg = new Regex(string.Format("[{0}]", Regex.Escape(regex)));
result = reg.Replace(source, "");
return result;
}
}
방법을 명확하게 사용할 수 있습니다.
파일 이름의 문자가 포함될 수 없습니다 Path.GetInvalidPathChars()
, +
및 #
기호 및 다른 특정 이름을. 모든 수표를 하나의 클래스로 결합했습니다.
public static class FileNameExtensions
{
private static readonly Lazy<string[]> InvalidFileNameChars =
new Lazy<string[]>(() => Path.GetInvalidPathChars()
.Union(Path.GetInvalidFileNameChars()
.Union(new[] { '+', '#' })).Select(c => c.ToString(CultureInfo.InvariantCulture)).ToArray());
private static readonly HashSet<string> ProhibitedNames = new HashSet<string>
{
@"aux",
@"con",
@"clock$",
@"nul",
@"prn",
@"com1",
@"com2",
@"com3",
@"com4",
@"com5",
@"com6",
@"com7",
@"com8",
@"com9",
@"lpt1",
@"lpt2",
@"lpt3",
@"lpt4",
@"lpt5",
@"lpt6",
@"lpt7",
@"lpt8",
@"lpt9"
};
public static bool IsValidFileName(string fileName)
{
return !string.IsNullOrWhiteSpace(fileName)
&& fileName.All(o => !IsInvalidFileNameChar(o))
&& !IsProhibitedName(fileName);
}
public static bool IsProhibitedName(string fileName)
{
return ProhibitedNames.Contains(fileName.ToLower(CultureInfo.InvariantCulture));
}
private static string ReplaceInvalidFileNameSymbols([CanBeNull] this string value, string replacementValue)
{
if (value == null)
{
return null;
}
return InvalidFileNameChars.Value.Aggregate(new StringBuilder(value),
(sb, currentChar) => sb.Replace(currentChar, replacementValue)).ToString();
}
public static bool IsInvalidFileNameChar(char value)
{
return InvalidFileNameChars.Value.Contains(value.ToString(CultureInfo.InvariantCulture));
}
public static string GetValidFileName([NotNull] this string value)
{
return GetValidFileName(value, @"_");
}
public static string GetValidFileName([NotNull] this string value, string replacementValue)
{
if (string.IsNullOrWhiteSpace(value))
{
throw new ArgumentException(@"value should be non empty", nameof(value));
}
if (IsProhibitedName(value))
{
return (string.IsNullOrWhiteSpace(replacementValue) ? @"_" : replacementValue) + value;
}
return ReplaceInvalidFileNameSymbols(value, replacementValue);
}
public static string GetFileNameError(string fileName)
{
if (string.IsNullOrWhiteSpace(fileName))
{
return CommonResources.SelectReportNameError;
}
if (IsProhibitedName(fileName))
{
return CommonResources.FileNameIsProhibited;
}
var invalidChars = fileName.Where(IsInvalidFileNameChar).Distinct().ToArray();
if(invalidChars.Length > 0)
{
return string.Format(CultureInfo.CurrentCulture,
invalidChars.Length == 1 ? CommonResources.InvalidCharacter : CommonResources.InvalidCharacters,
StringExtensions.JoinQuoted(@",", @"'", invalidChars.Select(c => c.ToString(CultureInfo.CurrentCulture))));
}
return string.Empty;
}
}
메소드가 GetValidFileName
모든 잘못된 데이터를로 바꿉니다 _
.
Windows 파일 이름 지정을 위해 불법 문자에서 문자열을 정리하는 하나의 라이너 :
public static string CleanIllegalName(string p_testName) => new Regex(string.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars())))).Replace(p_testName, "");
public static bool IsValidFilename(string testName)
{
return !new Regex("[" + Regex.Escape(new String(System.IO.Path.GetInvalidFileNameChars())) + "]").IsMatch(testName);
}
이것은 당신이 원하는 것을 원할 것이고 충돌을 피할 것입니다
static string SanitiseFilename(string key)
{
var invalidChars = Path.GetInvalidFileNameChars();
var sb = new StringBuilder();
foreach (var c in key)
{
var invalidCharIndex = -1;
for (var i = 0; i < invalidChars.Length; i++)
{
if (c == invalidChars[i])
{
invalidCharIndex = i;
}
}
if (invalidCharIndex > -1)
{
sb.Append("_").Append(invalidCharIndex);
continue;
}
if (c == '_')
{
sb.Append("__");
continue;
}
sb.Append(c);
}
return sb.ToString();
}
나는 그 질문이 아직 완전히 대답하지 않았다고 생각합니다 ... 대답은 깨끗한 파일 이름 또는 경로 만 설명합니다 ... 둘다는 아닙니다. 내 해결책은 다음과 같습니다.
private static string CleanPath(string path)
{
string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch)));
List<string> split = path.Split('\\').ToList();
string returnValue = split.Aggregate(string.Empty, (current, s) => current + (r.Replace(s, "") + @"\"));
returnValue = returnValue.TrimEnd('\\');
return returnValue;
}
몇 가지 제안을 결합한 확장 방법을 만들었습니다.
- 해시 세트에 잘못된 문자 보유
- ascii 127 아래의 문자 필터링. Path.GetInvalidFileNameChars에는 0에서 255까지의 ASCII 코드로 가능한 모든 유효하지 않은 문자가 포함되어 있지 않습니다. 여기 및 MSDN 참조
- 대체 문자를 정의 할 수 있음
출처:
public static class FileNameCorrector
{
private static HashSet<char> invalid = new HashSet<char>(Path.GetInvalidFileNameChars());
public static string ToValidFileName(this string name, char replacement = '\0')
{
var builder = new StringBuilder();
foreach (var cur in name)
{
if (cur > 31 && cur < 128 && !invalid.Contains(cur))
{
builder.Append(cur);
}
else if (replacement != '\0')
{
builder.Append(replacement);
}
}
return builder.ToString();
}
}
아니면 그냥 할 수 있습니다
[YOUR STRING].Replace('\\', ' ').Replace('/', ' ').Replace('"', ' ').Replace('*', ' ').Replace(':', ' ').Replace('?', ' ').Replace('<', ' ').Replace('>', ' ').Replace('|', ' ').Trim();
참고 URL : https://stackoverflow.com/questions/146134/how-to-remove-illegal-characters-from-path-and-filenames
'Programing' 카테고리의 다른 글
쉘에서 변수로 파일을 읽는 방법은 무엇입니까? (0) | 2020.02.20 |
---|---|
Swift에서 목록 항목의 색인을 찾는 방법은 무엇입니까? (0) | 2020.02.20 |
~ / .ssh / authorized_keys에 공개 키를 추가해도 자동으로 로그인되지 않습니다 (0) | 2020.02.20 |
파이썬의 time.clock () 대 time.time () 정확도? (0) | 2020.02.20 |
Node.js와 함께 사용할 웹 소켓 라이브러리는 무엇입니까? (0) | 2020.02.20 |