533

単純な文字列から不正なパスとファイルの文字を削除するための堅牢で簡単な方法が必要です。以下のコードを使用しましたが、何もしていないようです。何が欠けていますか?

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

30 に答える 30

534

代わりにこのようなことを試してください。

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

しかし、コメントに同意する必要があります。おそらく、違法なパスを正当ではあるがおそらく意図しないパスに変更しようとするのではなく、違法なパスのソースに対処しようとします。

編集:または、正規表現を使用した潜在的に「より良い」ソリューション。

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

それでも、そもそもなぜこれを行うのかという疑問が生じます。

于 2008-09-28T16:03:37.247 に答える
479

「不正な文字を削除する」ために尋ねられた元の質問:

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 による別のスレッドにありました。

于 2014-04-20T13:06:22.840 に答える
216

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

于 2011-09-12T20:38:10.900 に答える
93

次のように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());
于 2010-11-24T19:41:50.817 に答える
35

ファイル名の場合:

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

フルパスの場合:

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

これをセキュリティ機能として使用する場合は、すべてのパスを展開してから、ユーザーが指定したパスが実際にユーザーがアクセスできるディレクトリの子であることを確認することをお勧めします。

于 2014-02-11T02:36:30.980 に答える
29

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

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

Path.GetInvalidPathCharsそれはメソッドでは良くありません。まったく同じコメントが含まれています。

于 2011-11-16T13:22:36.687 に答える
18

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

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

于 2008-09-28T15:56:35.437 に答える
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 を呼び出して、検索と置換を行います。これは明らかに、パス文字もカバーするように拡張できます。

于 2008-09-28T18:45:24.453 に答える
13

私は絶対にジェフ・イェーツのアイデアを好みます。少し変更すると、完全に機能します。

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

改善は、自動生成された正規表現をエスケープすることです。

于 2011-02-15T14:21:46.727 に答える
12

.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, "");
    }
}
于 2010-10-19T16:33:56.250 に答える
8

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

wvd_vegt

于 2012-06-19T12:16:01.630 に答える
5

例外をスローします。

if ( fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 )
            {
                throw new ArgumentException();
            }
于 2009-03-12T16:14:16.197 に答える
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;
    }
}
于 2013-12-07T13:21:54.267 に答える
4

これは 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());
    }
于 2015-02-09T21:19:41.127 に答える
3

すべての不正な文字をチェックしようとするのではなく、正規表現を使用して許可される文字を指定する方がはるかに簡単に検証できると思います。次のリンクを参照して ください

また、「regular expression editor」を検索すると、非常に役立ちます。C# でコードを出力するものもあります。

于 2008-09-28T16:07:56.627 に答える
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;
        }
    }

方法が分かりやすく使えます。

于 2018-02-22T11:25:19.497 に答える
1
public static bool IsValidFilename(string testName)
{
    return !new Regex("[" + Regex.Escape(new String(System.IO.Path.GetInvalidFileNameChars())) + "]").IsMatch(testName);
}
于 2013-11-18T13:28:53.887 に答える
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;
}
于 2015-07-07T09:37:09.437 に答える
-6

または、あなたはただすることができます

[YOUR STRING].Replace('\\', ' ').Replace('/', ' ').Replace('"', ' ').Replace('*', ' ').Replace(':', ' ').Replace('?', ' ').Replace('<', ' ').Replace('>', ' ').Replace('|', ' ').Trim();
于 2014-01-15T21:24:52.693 に答える