경로와 파일 이름에서 잘못된 문자를 제거하는 방법은 무엇입니까?


456

간단한 문자열에서 잘못된 경로와 파일 문자를 제거하는 강력하고 간단한 방법이 필요합니다. 아래 코드를 사용했지만 아무것도하지 않는 것 같습니다. 무엇이 누락 되었습니까?

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

1
트림은 문자열의 시작과 끝에서 문자를 제거합니다. 그러나 데이터가 왜 유효하지 않은지 묻고 데이터를 삭제 / 제거하지 않고 데이터를 거부해야합니다.
user7116

8
유닉스 스타일 이름은 Windows에서 유효하지 않으며 8.3 짧은 이름을 처리하고 싶지 않습니다.
Gary Willoughby

GetInvalidFileNameChars()폴더 경로에서 : 등을 제거합니다.
CAD bloke 3

1
Path.GetInvalidPathChars()제거하지 않는 것 *또는?
CAD이 놈

18
이 질문에서 5 개의 답변 (시간 루프 100,000)을 테스트했으며 다음 방법이 가장 빠릅니다. 정규 표현식은 2 위를 차지했으며 25 % 느 렸습니다. public string GetSafeFilename (string filename) {return string.Join ( "_", filename.Split (Path.GetInvalidFileNameChars ())); }
Brain2000

답변:


494

대신 이와 같은 것을 시도하십시오.

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, "");

아직도, 질문은 구걸, 왜 당신이 처음에 이것을하고 있는지.


40
두 목록을 함께 추가 할 필요는 없습니다. 잘못된 파일 이름 char 목록에는 잘못된 경로 char 목록이 포함되어 있으며 몇 가지가 더 있습니다. 다음은 int로 캐스팅 된 두 목록의 목록입니다. 34,60,62,124,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,58,42,63,92,47 34,60,62,124,0,1,2 , 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27 , 28,29,30,31
Sarel Botha

9
@ sjbotha 이것은 Windows 및 Microsoft의 .NET 구현에서 사실 일 수 있습니다. 나는 모노 실행 Linux에 대해 동일한 가정을 기꺼이하지 않습니다.
Matthew Scharley

7
첫 번째 해결책에 관해서. StringBuilder가 문자열 할당보다 더 효율적이지 않아야합니까?
epignosisx

6
가치가있는 @MatthewScharley의 경우 GetInvalidPathChars ()의 모노 구현은 Windows 이외의 플랫폼에서 실행될 때 0x00 만 반환하고 GetInvalidFileNameChars ()는 0x00과 '/'만 반환합니다. Windows에서는 유효하지 않은 문자 목록이 훨씬 길고 GetInvalidPathChars ()가 GetInvalidFileNameChars () 내에서 완전히 복제됩니다. 이것은 미래에는 변하지 않을 것이기 때문에 유효한 경로의 정의가 언젠가 변경 될까 걱정하기 때문에이 기능을 실행하는 데 걸리는 시간을 두 배로 늘리는 것입니다. 그렇지 않습니다.
Warren Rumak

13
@Charleh이 토론은 너무 불필요합니다 ... 코드는 항상 최적화되어야하며 이것이 잘못 될 위험은 없습니다. 파일 이름도 경로의 일부입니다. 따라서 GetInvalidPathChars()문자를 포함 GetInvalidFileNameChars()하지 않는 것은 비논리적입니다 . "조기"최적화에 대한 정확성을 고려하지 않았습니다. 단순히 잘못된 코드를 사용하고 있습니다.
Stefan Fabian

353

원래 질문은 "잘못된 문자 제거"를 요청했습니다.

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의 또 다른 스레드에 있었으며 정말 깔끔하고 간단합니다.


10
OP의 질문에 정확하게 대답하려면 "_"대신 ""를 사용해야하지만 실제로는 더 많은 사람에게 답이 적용될 수 있습니다. 불법 문자를 합법적 인 문자로 바꾸는 것이 더 일반적이라고 생각합니다.
BH

36
이 질문에서 5 가지 방법 (10,000 회 반복 루프)을 테스트 했으며이 방법이 가장 빠릅니다. 정규 표현식은 2 위를 차지했으며이 방법보다 25 % 느 렸습니다.
Brain2000

10
@BH의 의견을 해결하기 위해 간단히 string.Concat (name.Split (Path.GetInvalidFileNameChars ()))을 사용할 수 있습니다
Michael Sutton

210

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


4
이것은 나를 위해 작동하지 않았습니다. 메소드가 클린 문자열을 리턴하지 않습니다. 전달 된 파일 이름을 그대로 반환합니다.
Karan

@Karan이 말한 것처럼, 이것이 작동하지 않으면 원래 문자열이 다시 나타납니다.
Jon

Linq를 사용하여 실제로 다음과 같이 할 수 있습니다 var invalid = new HashSet<char>(Path.GetInvalidPathChars()); return new string(originalString.Where(s => !invalid.Contains(s)).ToArray()). 성능은 좋지 않지만 아마 중요하지 않습니다.
Casey

2
@Karan 또는 Jon이 기능을 전송하는 입력은 무엇입니까? 이 방법의 검증에 대한 편집을 참조하십시오
Michael Minton

3
사람들은 유효한 문자로 문자열을 전달했습니다. 멋진 집계 솔루션으로 개선되었습니다.
Nickmaovich

89

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

1
나는이 방법을 좋아한다 : 허용 된 문자 만 문자열에 보관하십시오 (문자 배열 이외의 것은 아닙니다).
Dude Pascalou

6
나는 이것이 오래된 질문이라는 것을 알고 있지만 이것은 훌륭한 대답입니다. 그러나 C #에서는 char []에서 암시 적으로 또는 명시 적으로 문자열로 캐스트 할 수 없으므로 (미쳤습니다.) 문자열 생성자에 드롭해야한다고 덧붙였습니다.
JNYRanger

1
나는 이것을 확인하지는 않았지만 Path.GetInvalidPathChars ()가 GetInvalidFileNameChars ()의 상위 집합이기를 기대하고 파일 이름과 경로를 모두 포함하기를 기대합니다.
angularsen

3
@anjdreas 실제로 Path.GetInvalidPathChars ()는 Path.GetInvalidFileNameChars ()의 하위 집합 인 것 같습니다. 예를 들어 Path.GetInvalidPathChars ()는 '?'를 반환하지 않습니다.
Rafael Costa

1
이것은 좋은 대답입니다. 파일 이름 목록과 파일 경로 목록을 모두 사용합니다. ____________________________ string cleanData = new string (data.Where (x =>! Path.GetInvalidFileNameChars (). Contains (x) &&! Path.GetInvalidPathChars (). Contains (x)). ToArray ());
goamn

27

이것들은 모두 훌륭한 솔루션이지만, 모두 Path.GetInvalidFileNameChars신뢰할 수있는 것입니다. MSDN 설명서에서 Path.GetInvalidFileNameChars다음 내용 을 확인하십시오 .

이 메소드에서 리턴 된 배열 은 파일 및 디렉토리 이름에 유효하지 않은 전체 문자 세트를 포함하지 않을 수 있습니다. 유효하지 않은 문자의 전체 세트는 파일 시스템에 따라 다를 수 있습니다. 예를 들어, Windows 기반 데스크탑 플랫폼에서 유효하지 않은 경로 문자는 ASCII / 유니 코드 문자 1-31뿐만 아니라 따옴표 ( "), (<)보다 작음 (<),보다 큼 (>), 파이프 (|), 백 스페이스 ( \ b), null (\ 0) 및 탭 (\ t)입니다.

Path.GetInvalidPathChars방법으로는 나아지지 않습니다 . 똑같은 말이 들어 있습니다.


13
그렇다면 Path.GetInvalidFileNameChars의 요점은 무엇입니까? 현재 시스템에 대해 유효하지 않은 문자를 정확하게 반환하고 .NET을 사용하여 실행중인 파일 시스템을 알 수 있으며 적합하지 않은 문자를 제시합니다. 그렇지 않은 경우 처음에는 신뢰할 수없는 하드 코드 된 문자 만 리턴하면이 메소드는 값이 0이므로 제거해야합니다.
Jan

1
나는 이것이 오래된 의견이라는 것을 알고 있지만 @Jan 다른 파일 시스템에 쓰고 싶을 수도 있습니다. 아마도 이것이 경고가있는 이유입니다.
fantastik78

3
@ fantastik78 좋은 지적이지만이 경우 원격 FS를 지정하기 위해 추가 열거 형 인수를 원합니다. 이것이 유지 관리 노력이 너무 많은 경우 (대부분의 경우),이 전체 방법은 안전에 대한 잘못된 인상을주기 때문에 여전히 나쁜 생각입니다.
Jan

1
@ 1 월 나는 당신에게 전적으로 동의한다, 나는 단지 경고에 관해 논쟁하고 있었다.
fantastik78

흥미롭게도 이것은 일종의 "블랙리스트"무효 문자입니다. 알려진 유효한 문자 만 "허용"하는 것이 좋지 않습니까?! 허용 된 앱을 허용 목록에 추가하는 대신 어리석은 "바이러스 검색 프로그램"아이디어를 생각 나게합니다 ....
Bernhard

26

파일 이름의 경우 :

var cleanFileName = string.Join("", fileName.Split(Path.GetInvalidFileNameChars()));

전체 경로 :

var cleanPath = string.Join("", path.Split(Path.GetInvalidPathChars()));

이 기능을 보안 기능으로 사용하려는 경우보다 강력한 방법은 모든 경로를 확장 한 다음 사용자 제공 경로가 사용자가 액세스 할 수있는 디렉토리의 하위 항목인지 확인하는 것입니다.


18

우선 Trim은 문자열의 시작 또는 끝에서 문자 만 제거합니다 . 두 번째로, 공격적인 문자를 실제로 제거 할 것인지 평가하거나 빠르게 실패하여 파일 이름이 잘못되었음을 사용자에게 알려야합니다. 내 선택은 후자이지만, 내 대답은 적어도 옳고 그른 방법으로 일을하는 방법을 보여 주어야합니다.

주어진 문자열이 유효한 파일 이름인지 확인하는 방법을 보여주는 StackOverflow 질문 . 이 질문에서 정규 표현식을 사용하여 정규 표현식 대체 문자를 제거 할 수 있습니다 (실제로이 작업을 수행 해야하는 경우).


나는 특히 두 번째 조언에 동의합니다.
OregonGhost

4
나는 일반적으로 두 번째에 동의하지만 파일 이름을 생성하고 일부 상황에서 잘못된 문자를 포함 할 수있는 프로그램이 있습니다. 내 프로그램 이 잘못된 파일 이름을 생성하고 있으므로 해당 문자를 제거 / 교체하는 것이 적절하다고 생각합니다. (유효한 사용 사례 만 지적)
JDB는 여전히 Monica

16

사용자 입력에서 잘못된 문자를 제거하는 가장 좋은 방법은 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">

5
IMHO이 솔루션은 다른 솔루션보다 훨씬 낫습니다. 모든 유효하지 않은 문자를 검색하는 대신 유효한 문자를 정의하십시오.
igorushi

15

나는 이것을 달성하기 위해 정규 표현식을 사용합니다. 먼저 정규식을 동적으로 작성합니다.

string regex = string.Format(
                   "[{0}]",
                   Regex.Escape(new string(Path.GetInvalidFileNameChars())));
Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

그런 다음 removeInvalidChars.Replace를 호출하여 찾기 및 바꾸기를 수행합니다. 이것은 경로 문자를 포함하도록 분명히 확장 될 수 있습니다.


이상해, 그것은 나를 위해 일하고있다. 기회가 생기면 다시 확인하겠습니다. 더 구체적이고 당신에게 효과가없는 것을 설명 할 수 있습니까?
Jeff Yates

1
경로 문자를 올바르게 이스케이프하지 않고 일부는 특별한 의미가 있기 때문에 (적어도 적절하게는) 작동하지 않습니다. 그렇게하는 방법에 대한 내 대답을 참조하십시오.
Matthew Scharley

@ Jeff : 약간 수정하면 버전이 Matthew보다 좋습니다. 방법에 대한 내 대답을 참조하십시오.
1

2
또한 MSDN 에서 찾을 수있는 다른 잘못된 파일 이름 패턴을 추가하고 솔루션을 다음 정규식으로 확장합니다.new Regex(String.Format("^(CON|PRN|AUX|NUL|CLOCK\$|COM[1-9]|LPT[1-9])(?=\..|$)|(^(\.+|\s+)$)|((\.+|\s+)$)|([{0}])", Regex.Escape(new String(Path.GetInvalidFileNameChars()))), RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.CultureInvariant);
yar_shukan

13

나는 Jeff Yates의 아이디어를 절대적으로 선호합니다. 약간 수정하면 완벽하게 작동합니다.

string regex = String.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars())));
Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

개선 된 기능은 자동으로 생성 된 정규식을 피하는 것입니다.


11

다음은 .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, "");
    }
}

8

위의 대부분의 솔루션은 경로와 파일 이름 모두에 잘못된 문자를 결합합니다 (두 호출이 현재 동일한 문자 집합을 반환하더라도). 먼저 경로와 파일 이름에서 경로 + 파일 이름을 분할 한 다음 적절한 세트를 적용하고 둘을 다시 결합하십시오.

wvd_vegt


+1 : 매우 그렇습니다. 오늘날 .NET 4.0에서 일하면서 최상위 답변의 정규식 솔루션은 모든 백 슬래시를 완전히 뒤흔들 었습니다. 그래서 나는 dir 경로에 대한 정규 표현식과 파일 이름에 대한 정규 표현식을
만들었고

사실 일 수도 있지만 질문에 대한 답은 아닙니다. 모호한 '이런 식으로 할 것'은 이미 여기에있는 일부 완전한 솔루션에 비해 대단히 도움이된다고 확신하지 않습니다 (예 : Lilly의 답변 참조)
Ian Grainger

6

유효하지 않은 문자를 단일 문자로 제거하거나 바꾸면 충돌이 발생할 수 있습니다.

<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

5

예외를 던지십시오.

if ( fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 )
            {
                throw new ArgumentException();
            }

4

나는이 괴물을 재미있게 썼다.

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

1
나는 동일한 결과 경로를 만드는 두 개의 다른 문자열을 피하기 때문에 이것을 좋아합니다.
Kim

3

모든 나쁜 문자를 확인하는 대신 정규식을 사용하고 허용되는 문자를 지정하는 것이 훨씬 쉽다고 생각합니다. 다음 링크를 참조하십시오. http://www.c-sharpcorner.com/UploadFile/prasad_1/RegExpPSD12062005021717AM/RegExpPSD.aspx http://www.windowsdevcenter.com/pub/a/oreilly/windows/news/csharp_0101.html

또한 "정규 표현식 편집기"를 검색하면 많은 도움이됩니다. C #으로 코드를 출력하는 곳도 있습니다.


.net은 여러 플랫폼 (예 : Linux / Unix 및 Windows)에서 프로그램을 실행할 수 있도록 고안된 프레임 워크이므로 Path.GetInvalidFileNameChars ()가 무엇인지에 대한 지식이 들어 있기 때문에 가장 좋습니다. t 프로그램이 실행되고있는 파일 시스템에서 유효합니다. 프로그램이 Linux에서 절대 실행되지 않더라도 (WPF 코드로 가득 차있을 수 있음), 향후 일부 새로운 Windows 파일 시스템이 등장하여 다른 유효 / 무효 문자가있을 가능성은 항상 있습니다. 정규식으로 자신을 굴리는 것은 바퀴를 재창조하고 플랫폼 문제를 자신의 코드로 바꿉니다.
Daniel Scott

온라인 정규식 편집자 / 테스터에 대한 귀하의 조언에 동의합니다. 나는 그것들이 귀중한 것을 발견합니다 (정규는 까다 롭고 쉽게 넘어 질 수있는 미묘함으로 가득 차 있기 때문에 가장자리 케이스와 함께 예기치 않은 방식으로 행동하는 정규 표현식을 제공합니다). 내가 가장 좋아하는 것은 regex101.com입니다 (정규식을 분류하고 일치하는 것을 명확하게 보여주는 방법 이 마음에 듭니다 ). 또한 matchge 그룹과 문자 클래스 등을 간결하게 시각적으로 표시하므로 debuggex.com 을 매우 좋아 합니다.
Daniel Scott

3

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

1
'Any'기능을 사용할 때 O (n)이라고 생각하지 않습니다.
II Arrows

@IIARROWS 그리고 당신의 의견은 무엇입니까?
Alexey F

잘 모르겠습니다. 내 의견을 쓸 때 느낌이 들지 않았습니다 ... 이제 계산하려고 시도한 결과가 옳아 보입니다.
II Arrows

성능 고려 사항으로 인해 이것을 선택했습니다. 감사.
Berend Engelbrecht '10

3

여기에 대한 답변을 살펴보면 모두 유효하지 않은 파일 이름 문자의 문자 배열을 사용하는 것 같습니다.

물론 이것은 미세 최적화 일 수 있지만 유효한 파일 이름으로 많은 수의 값을 확인하려는 사람들의 이익을 위해 유효하지 않은 문자의 해시 세트를 작성하면 성능이 현저히 향상된다는 점에 주목할 가치가 있습니다.

과거에 해시 세트 (또는 사전)가 목록을 반복하는 것보다 얼마나 빨리 성능을 발휘했는지 놀랐습니다. 문자열을 사용하면 엄청나게 낮은 숫자입니다 (메모리에서 약 5-7 항목). 대부분의 다른 간단한 데이터 (객체 참조, 숫자 등)에서 매직 크로스 오버는 약 20 개 항목 인 것 같습니다.

Path.InvalidFileNameChars "list"에 40 개의 유효하지 않은 문자가 있습니다. 오늘 검색을 해보았 고 여기에 40 개의 항목에 대한 해시 세트가 배열 / 목록 시간의 절반 이상을 차지한다는 것을 보여주는 StackOverflow에 대한 훌륭한 벤치 마크가 있습니다 : https://stackoverflow.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;
    }
}

2
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;
        }
    }

방법을 명확하게 사용할 수 있습니다.


2

파일 이름의 문자가 포함될 수 없습니다 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모든 잘못된 데이터를로 바꿉니다 _.


2

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, "");

1
public static bool IsValidFilename(string testName)
{
    return !new Regex("[" + Regex.Escape(new String(System.IO.Path.GetInvalidFileNameChars())) + "]").IsMatch(testName);
}

0

이것은 당신이 원하는 것을 원할 것이고 충돌을 피할 것입니다

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

    }

0

나는 그 질문이 아직 완전히 대답하지 않았다고 생각합니다 ... 대답은 깨끗한 파일 이름 또는 경로 만 설명합니다 ... 둘다는 아닙니다. 내 해결책은 다음과 같습니다.

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

0

몇 가지 제안을 결합한 확장 방법을 만들었습니다.

  1. 해시 세트에 잘못된 문자 보유
  2. Path.GetInvalidFileNameChars 때문에 ASCII 127 아래의 문자를 필터링하면 0에서 255까지 아스키 코드로 가능한 모든 잘못된 문자가 포함되지 않습니다 여기를 참조MSDN을
  3. 대체 문자를 정의 할 수 있음

출처:

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

0

다음은 파일 이름의 모든 잘못된 문자를 대체 문자로 바꾸는 기능입니다.

public static string ReplaceIllegalFileChars(string FileNameWithoutPath, char ReplacementChar)
{
  const string IllegalFileChars = "*?/\\:<>|\"";
  StringBuilder sb = new StringBuilder(FileNameWithoutPath.Length);
  char c;

  for (int i = 0; i < FileNameWithoutPath.Length; i++)
  {
    c = FileNameWithoutPath[i];
    if (IllegalFileChars.IndexOf(c) >= 0)
    {
      c = ReplacementChar;
    }
    sb.Append(c);
  }
  return (sb.ToString());
}

예를 들어 밑줄을 대체 문자로 사용할 수 있습니다.

NewFileName = ReplaceIllegalFileChars(FileName, '_');

제공 한 답변 외에도 문제가 해결되는 이유와 방법에 대한 간단한 설명을 제공하십시오.
jtate

-7

아니면 그냥 할 수 있습니다

[YOUR STRING].Replace('\\', ' ').Replace('/', ' ').Replace('"', ' ').Replace('*', ' ').Replace(':', ' ').Replace('?', ' ').Replace('<', ' ').Replace('>', ' ').Replace('|', ' ').Trim();
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.