パスとファイル名から不正な文字を削除するにはどうすればよいですか?


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
Trimは、文字列の最初と最後から文字を削除します。ただし、おそらくデータが無効である理由を尋ね、データをサニタイズ/修正するのではなく、データを拒否する必要があります。
user7116 2008

8
Unixスタイル名はWindowsでは無効であり、8.3ショートネームを処理したくありません。
ゲイリーウィロビー

GetInvalidFileNameChars()フォルダパスから:\などのようなものを削除します。
CADが2016年

1
Path.GetInvalidPathChars()ストリップしていないようです*?
CADやつ

19
私はこの質問から5つの回答(100,000のタイミングループ)をテストしました。次の方法が最も高速です。正規表現が2位になり、25%遅くなりました。public string GetSafeFilename(string filename){return string.Join( "_"、filename.Split(Path.GetInvalidFileNameChars())); }
Brain2000 2016

回答:


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
2つのリストを一緒に追加する必要はありません。不正なファイル名の文字リストには、不正なパスの文字リストが含まれ、さらにいくつかあります。以下は、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
Botha

9
@sjbothaこれは、WindowsとMicrosoftの.NETの実装に当てはまる可能性があります。
Matthew Scharley、2011

7
最初の解決策について。StringBuilderは文字列の割り当てよりも効率的ではないでしょうか?
epignosisx 2011

6
@MatthewScharleyの場合、Windows以外のプラットフォームで実行している場合、GetInvalidPathChars()のMono実装は0x00のみを返し、GetInvalidFileNameChars()は0x00と '/'だけを返します。Windowsでは、無効な文字のリストははるかに長くなり、GetInvalidPathChars()はGetInvalidFileNameChars()内で完全に複製されます。これは近い将来に変更されることはないので、有効なパスの定義がすぐに変更されるのではないかと心配しているため、この関数の実行にかかる時間を2倍にするだけです。それはしません。
Warren Rumak 2014年

13
@Charlehこの議論はとても不必要です...コードは常に最適化されるべきであり、これが不正確になるリスクはありません。ファイル名もパスの一部です。だから、そうではないGetInvalidPathChars()文字を含むことができるのは単に非論理的ですGetInvalidFileNameChars()。「時期尚早」の最適化よりも正確ではありません。あなたは単に悪いコードを使用しています。
Stefan Fabian

355

元の質問は「不正な文字を削除する」よう求めました:

public string RemoveInvalidChars(string filename)
{
    return string.Concat(filename.Split(Path.GetInvalidFileNameChars()));
}

代わりにそれらを置き換えることもできます。

public string ReplaceInvalidChars(string filename)
{
    return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));    
}

この答えはセレスの別のスレッドでした、私はそれがすっきりとシンプルで本当に好きです。


10
OPの質問に正確に回答するには、「_」の代わりに「」を使用する必要がありますが、実際の回答はおそらくより多くの私たちに当てはまります。違法な文字を合法的な文字に置き換えるのがより一般的だと思います。
BH 2016年

37
私はこの質問から5つの方法(100,000のタイミングループ)をテストしましたが、この方法が最速です。正規表現は2位になり、この方法よりも25%遅くなりました。
Brain2000 2016

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 2013

@カランが言ったこと、これは機能しません、元の文字列が戻ってきます。
Jon

ただし、実際には次のようなLinqでこれを行うことができます var invalid = new HashSet<char>(Path.GetInvalidPathChars()); return new string(originalString.Where(s => !invalid.Contains(s)).ToArray())。パフォーマンスはおそらく素晴らしいものではありませんが、それはおそらく問題ではありません。
ケーシー

2
@KaranまたはJonこの関数に送信する入力は何ですか?このメソッドの検証については、私の編集を参照してください。
Michael Minton、2015

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
私はこの方法が好きです:許可された文字だけを文字列に保持します(これは文字配列にすぎません)。
デュードパスカロウ

6
これは古い質問であることは知っていますが、これは素晴らしい答えです。ただし、c#では暗黙的または明示的にchar []から文字列にキャストできないため(クレイジー、わかっています)、それを文字列コンストラクターにドロップする必要があることを追加しました。
JNYRanger 2014年

1
私はこれを確認していませんが、Path.GetInvalidPathChars()がGetInvalidFileNameChars()のスーパーセットであり、ファイル名とパスの両方をカバーすることを期待しているので、おそらく代わりにそれを使用します。
Angularsen、2015年

3
@anjdreasは実際にはPath.GetInvalidPathChars()はPath.GetInvalidFileNameChars()のサブセットであり、逆ではないようです。たとえば、Path.GetInvalidPathChars()は '?'を返しません。
ラファエルコスタ

1
これは良い答えです。ファイル名リストとファイルパスリストの両方を使用します。____________________________string cleanData = new string(data.Where(x =>!Path.GetInvalidFileNameChars()。Contains(x)&&!Path.GetInvalidPathChars()。Contains(x))。 ToArray());
goamn 2017年

27

これらはすべて優れたソリューションですが、すべて信頼しているためPath.GetInvalidFileNameChars、思ったほど信頼性が高くない場合があります。に関するMSDNドキュメントの次の注釈に注意してくださいPath.GetInvalidFileNameChars

このメソッドから返される配列には、ファイル名とディレクトリ名で無効な文字の完全なセットが含まれているとは限りません。無効な文字の完全なセットは、ファイルシステムによって異なります。たとえば、Windowsベースのデスクトッププラットフォームでは、無効なパス文字には、ASCII / Unicode文字1〜31、および引用符( ")、小なり(<)、大なり(>)、パイプ(|)、バックスペース( \ b)、null(\ 0)およびタブ(\ t)。

それは、Path.GetInvalidPathCharsメソッドを使用した場合、それ以上良くはありません。まったく同じ発言が含まれています。


13
次に、Path.GetInvalidFileNameCharsのポイントは何ですか?私はそれが現在のシステムの正確に無効な文字を返すことを期待します。.NETに依存して、実行しているファイルシステムを認識し、適切な無効な文字を表示します。これが当てはまらず、そもそもハードコードされた文字を返すだけの場合は信頼できない場合、このメソッドは値がゼロであるため削除する必要があります。
Jan

1
私はこれが古いコメントであることを知っていますが、@ Janあなたは別のファイルシステムに書きたいと思うかもしれません、おそらくこれが警告がある理由です。
fantastik78

3
@ fantastik78良い点ですが、この場合、リモートFSを指定するための追加のenum引数が必要です。これがあまりにも多くのメンテナンス作業である場合(これは最も可能性が高いケースです)、この方法全体は、安全性の誤った印象を与えるため、依然として悪い考えです。
Jan

1
@Jan私はあなたに完全に同意します、私は警告について議論していました。
fantastik78

興味深いことに、これは一種の「ブラックリスト」の無効な文字です。ここで既知の有効な文字だけを「ホワイトリストに登録」する方が良いでしょうか?!許可されたアプリをホワイトリストに登録する代わりに、愚かな "virusscanner"のアイデアを思い出します...
Bernhard

26

ファイル名の場合:

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

完全パスの場合:

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

これをセキュリティ機能として使用する場合、より堅牢なアプローチは、すべてのパスを展開し、ユーザーが指定したパスが、ユーザーがアクセスできるディレクトリの子であることを確認することです。


18

まず、Trimは文字列の最初または最後から文字のみを削除します。次に、不快な文字を本当に削除したいかどうか、またはすぐに失敗してファイル名が無効であることをユーザーに知らせるかどうかを評価する必要があります。私の選択は後者ですが、私の答えは少なくとも物事を正しい方法と間違った方法で行う方法を示すはずです:

特定の文字列が有効なファイル名であるかどうかを確認する方法を示すStackOverflowの質問。この質問の正規表現を使用して、正規表現を置換して文字を削除することができます(本当にこれが必要な場合)。


特に2番目のアドバイスに同意します。
OregonGhost 2008

4
通常は2番目に同意しますが、ファイル名を生成し、状況によっては不正な文字を含むプログラムがあります。私のプログラムは不正なファイル名を生成しているのでそれらの文字を削除/置換するのが適切だと思います。(有効なユースケースを指摘しているだけです)
JDBはモニカを2013

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
私見このソリューションは他のソリューションよりもはるかに優れていますすべての無効な文字を検索するのではなく、有効な文字を定義するだけです。
イゴルシ2015

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を呼び出して検索と置換を行います。これは明らかにパス文字をカバーするように拡張できます。


奇妙なことに、それは私のために働いています。機会があれば再確認します。もっと具体的に説明して、何がうまくいかないのか正確に説明できますか?
ジェフイェーツ2010

1
パス文字を適切にエスケープしておらず、一部には特別な意味があるため、(少なくとも適切には)機能しません。その方法については私の回答を参照してください。
Matthew Scharley、2010

@ジェフ:少し変更すれば、バージョンはマシューのバージョンよりも優れています。方法については私の回答を参照してください。

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

私はジェフ・イェーツの考えを絶対に好みます。少し変更すれば、完全に機能します。

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

上記のほとんどのソリューションは、パスとファイル名の両方に不正な文字を組み合わせていますが、これは誤りです(両方の呼び出しが現在同じ文字セットを返す場合でも)。最初にパスとファイル名をパスとファイル名に分割し、適切なセットをどちらかに適用してから、2つを再度結合します。

wvd_vegt


+1:とてもそうです。今日、.NET 4.0で作業しているトップアンサーの正規表現ソリューションは、すべてのバックスラッシュをフルパスで割り出しました。したがって、dirパスの正規表現とファイル名だけの正規表現を作成し、個別にクリーンアップして再結合しました
dario_ramos

それは本当かもしれませんが、これは質問に答えません。ここに既にある完全なソリューションのいくつかと比較して、漠然とした「私はこのようにする」が非常に役立つかどうかわかりません(たとえば、以下のリリーの回答を参照)
Ian Grainger

6

無効な文字を1つの文字で削除または置き換えると、競合が発生する可能性があります。

<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
2つの異なる文字列が同じ結果のパスを作成するのを回避できるので、私はこれが好きです。
キム

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()は、何であるか、または何であるかに関する知識が含まれるため、最良であると感じますプログラムが実行されているファイルシステムで有効です。プログラムがLinuxで実行されない場合でも(おそらくWPFコードでいっぱいです)、新しいWindowsファイルシステムが将来登場し、異なる有効/無効文字を持つ可能性は常にあります。正規表現を使用して独自のロールを行うことは、車輪を再発明し、プラットフォームの問題を独自のコードにシフトすることです。
ダニエルスコット

オンラインの正規表現エディター/テスターに​​ついてのアドバイスにも同意します。私はそれらを非常に貴重だと思っています(正規表現はトリッキーなものであり、簡単につまずくことができる微妙な点がたくさんあるので、エッジケースで非常に予期しない方法で動作する正規表現を提供します)。私のお気に入りは regex101.comです(正規表現を分解し、一致するものを明確に示す方法)。debuggex.comはマッチグループや文字クラスなどのコンパクトな視覚表現を備えているため、私も非常に気に入っています。
ダニエルスコット

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アローズ

@IIARROWSとは何ですか?
Alexey F

わかりません。コメントを書いたときは、そのようには感じられませんでした...計算しようとしたので、あなたは正しいようです。
IIアローズ

パフォーマンスを考慮してこれを選択しました。ありがとう。
Berend Engelbrecht

3

ここで答えを調べてみると、それらはすべて、無効なファイル名文字のchar配列を使用しているようです。

確かに、これは微妙に最適化される可能性があります。ただし、多数の値をチェックして有効なファイル名であることを確認しようとしている人のために、無効な文字のハッシュセットを作成すると、パフォーマンスが著しく向上することに注意してください。

ハッシュセット(またはディクショナリ)がリストの反復処理をどれほど速く実行するかは、これまで非常に驚きました(ショックを受けました)。文字列では、それは途方もなく低い数です(メモリから約5〜7項目)。他のほとんどの単純なデータ(オブジェクト参照、数値など)では、魔法のクロスオーバーは約20アイテムのようです。

Path.InvalidFileNameChars "リスト"に40の無効な文字があります。今日検索を行ったところ、StackOverflowにはかなり良いベンチマークがあり、ハッシュセットが配列/リストの40項目の半分の時間を少し超えることを示しています: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()+#記号、および他の特定の名前を。すべてのチェックを1つのクラスにまとめました。

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ファイル名の不正な文字から文字列をクリーンアップする1つのライナー:

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. ascii 127以下の文字を除外します。Path.GetInvalidFileNameCharsには、0〜255のASCIIコードで可能なすべての無効な文字が含まれていないため、こちら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.