it-swarm.com.de

Wie entferne ich illegale Zeichen aus Pfad und Dateinamen?

Ich brauche eine robuste und einfache Möglichkeit, illegale Pfad- und Dateizeichen aus einer einfachen Zeichenfolge zu entfernen. Ich habe den folgenden Code verwendet, aber er scheint nichts zu tun. Was fehlt mir?

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

Versuchen Sie stattdessen etwas davon.

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

Aber ich muss den Kommentaren zustimmen, ich würde wahrscheinlich versuchen, mit der Quelle der illegalen Pfade umzugehen, anstatt einen illegalen Pfad in einen legitimen, aber wahrscheinlich unbeabsichtigten Pfad zu manipulieren.

Bearbeiten: Oder eine möglicherweise "bessere" Lösung mit 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, "");

Dennoch stellt sich die Frage, warum man das überhaupt macht.

448
public string GetSafeFilename(string filename)
{

    return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));

}

Diese Antwort war in einem anderen Thread von Ceres , ich mag es wirklich ordentlich und einfach.

234
Shehab Fawzy

Ich benutze Linq, um Dateinamen zu bereinigen. Sie können dies leicht erweitern, um auch nach gültigen Pfaden zu suchen.

private static string CleanFileName(string fileName)
{
    return Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty));
}

Aktualisieren

Einige Kommentare weisen darauf hin, dass diese Methode für sie nicht funktioniert. Daher habe ich einen Link zu einem DotNetFiddle-Snippet eingefügt, damit Sie die Methode überprüfen können. 

https://dotnetfiddle.net/nw1SWY

203
Michael Minton

Sie können illegale Zeichen mit Linq wie folgt entfernen:

var invalidChars = Path.GetInvalidFileNameChars();

var invalidCharsRemoved = stringWithInvalidChars
.Where(x => !invalidChars.Contains(x))
.ToArray();

EDIT
So sieht es mit der erforderlichen Änderung aus, die in den Kommentaren erwähnt wird:

var invalidChars = Path.GetInvalidFileNameChars();

string invalidCharsRemoved = new string(stringWithInvalidChars
  .Where(x => !invalidChars.Contains(x))
  .ToArray());
84
Gregor Slavec

Dies sind alles hervorragende Lösungen, die jedoch alle auf Path.GetInvalidFileNameChars angewiesen sind, was möglicherweise nicht so zuverlässig ist, wie Sie denken. Beachten Sie die folgende Anmerkung in der MSDN-Dokumentation zu Path.GetInvalidFileNameChars :

Das von dieser Methode zurückgegebene Array enthält garantiert nicht den vollständigen Satz von Zeichen, die in Datei- und Verzeichnisnamen ungültig sind. Der vollständige Satz ungültiger Zeichen kann je nach Dateisystem variieren. Auf Windows-basierten Desktop-Plattformen können ungültige Pfadzeichen beispielsweise ASCII/Unicode-Zeichen 1 bis 31 sowie Anführungszeichen ("), kleiner als (<), größer als (>), Pipe (|), Rücktaste (\b), null (\ 0) und tab (\ t).

Mit der Path.GetInvalidPathChars -Methode ist es nicht besser. Es enthält genau dieselbe Bemerkung.

26
René

Für den Anfang entfernt Trim nur Zeichen vom Anfang oder Ende der Zeichenfolge . Zweitens sollten Sie prüfen, ob Sie die beleidigenden Zeichen wirklich entfernen möchten, oder schnell ausfallen und den Benutzer darüber informieren, dass der Dateiname ungültig ist. Meine Wahl ist das letztere, aber meine Antwort sollte Ihnen zumindest zeigen, wie Sie die Dinge richtig und falsch machen:

StackOverflow-Frage, die zeigt, wie geprüft wird, ob eine angegebene Zeichenfolge ein gültiger Dateiname ist . Beachten Sie, dass Sie den regulären Ausdruck aus dieser Frage verwenden können, um Zeichen mit einem regulären Ausdruck zu ersetzen (falls dies wirklich erforderlich ist).

18
user7116

Für Dateinamen:

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

Für vollständige Pfade:

string cleanPath = String.Join("", path.Split(Path.GetInvalidPathChars()));
16
Lily Finley

Ich verwende dafür reguläre Ausdrücke. Zuerst baue ich den Regex dynamisch auf.

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

Dann rufe ich einfach removeInvalidChars.Replace auf, um das Suchen und Ersetzen durchzuführen. Dies kann natürlich auch auf die Zeichenabschnitte ausgedehnt werden.

15
Jeff Yates

Der beste Weg, illegale Zeichen aus Benutzereingaben zu entfernen, ist das Ersetzen ungültiger Zeichen mithilfe der Regex-Klasse, das Erstellen einer Methode im Code dahinter oder das Überprüfen auf Client-Seite mithilfe der RegularExpression-Steuerung.

public string RemoveSpecialCharacters(string str)
{
    return Regex.Replace(str, "[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled);
}

ODER

<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">
14
anomepani

Ich ziehe die Idee von Jeff Yates absolut vor. Es funktioniert perfekt, wenn Sie es leicht ändern:

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

Die Verbesserung besteht nur darin, dem automatisch generierten Regex zu entgehen.

14
Jan

Hier ist ein Code-Snippet, der für .NET 3 und höher hilfreich sein sollte.

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

Die meisten obigen Lösungen kombinieren unzulässige Zeichen für Pfad und Dateinamen, was falsch ist (auch wenn beide Aufrufe derzeit denselben Zeichensatz zurückgeben). Ich würde zuerst Pfad + Dateiname in Pfad und Dateiname aufteilen, dann den entsprechenden Satz auf beide anwenden und dann die beiden erneut kombinieren.

wvd_vegt

8
wvd_vegt

Wenn Sie die ungültigen Zeichen entfernen oder durch ein einzelnes Zeichen ersetzen, können Kollisionen auftreten:

<abc -> abc
>abc -> abc

Hier ist eine einfache Methode, um dies zu vermeiden:

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

Das Ergebnis:

 <abc -> [1]abc
 >abc -> [2]abc
6
Maxence

Eine Ausnahme auslösen.

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

Ich habe dieses Monster zum Spaß geschrieben.

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;
    }
}
4
Johan Larsson

Ich denke, es ist viel einfacher, mit einem Regex zu validieren und festzulegen, welche Zeichen erlaubt sind, anstatt zu versuchen, nach allen schlechten Zeichen zu suchen. Siehe folgende Links: http: //www.c-sharpcorner. com/UploadFile/prasad_1/RegExpPSD12062005021717AM/RegExpPSD.aspxhttp://www.windowsdevcenter.com/pub/a/oreilly/windows/news/csharp_0101.html

Suchen Sie auch nach regulären Ausdruckseditoren, sie helfen sehr. Es gibt einige, um die sogar der Code in c # für Sie ausgegeben wird.

3

Dies scheint O(n) zu sein und verbraucht nicht zu viel Speicher für Strings:

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

Sie können die Methode eindeutig verwenden. 

2
aemre

Ein Liner, der Zeichenfolgen von ungültigen Zeichen für die Benennung von Windows-Dateien entfernt:

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

Wenn Sie die Antworten hier scannen, scheint es sich bei allen ** um ein Array mit ungültigen Dateinamen zu handeln. 

Zugegeben, dies kann mikrooptimierend sein - aber zum Vorteil aller, die eine große Anzahl von Werten auf gültige Dateinamen überprüfen möchten, ist es erwähnenswert, dass der Aufbau eines Hashsatzes ungültiger Zeichen eine merklich bessere Leistung bringt. 

Ich war in der Vergangenheit sehr überrascht (schockiert), wie schnell ein Hashset (oder Wörterbuch) eine Liste durchläuft. Bei Strings ist das eine lächerlich niedrige Zahl (ungefähr 5-7 Elemente aus dem Speicher). Bei den meisten anderen einfachen Daten (Objektreferenzen, Zahlen usw.) scheint die magische Überkreuzung bei etwa 20 Elementen zu liegen. 

In der Path.InvalidFileNameChars- "Liste" befinden sich 40 ungültige Zeichen. Habe heute eine Suche durchgeführt und es gibt einen ziemlich guten Benchmark auf StackOverflow, der zeigt, dass das Hashset etwas mehr als die Hälfte der Zeit eines Arrays/einer Liste für 40 Elemente benötigt: https://stackoverflow.com/a/10762995/949129

Hier ist die Helferklasse, die ich für die Desinfektion von Pfaden verwende. Ich habe jetzt vergessen, warum ich die ausgefallene Ersatzoption dabei hatte, aber es ist ein netter Bonus.

Zusätzliche Bonusmethode "IsValidLocalPath" auch :)

(** diejenigen, die keine regulären Ausdrücke verwenden)

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
Daniel Scott
public static bool IsValidFilename(string testName)
{
    return !new Regex("[" + Regex.Escape(new String(System.IO.Path.GetInvalidFileNameChars())) + "]").IsMatch(testName);
}
1
mbdavis

Der Dateiname darf keine Zeichen aus den Symbolen Path.GetInvalidPathChars(), + und # sowie andere spezifische Namen enthalten. Wir haben alle Schecks in einer Klasse zusammengefasst:

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

Die Methode GetValidFileName ersetzt alle falschen Daten in _.

1
Backs

Ich habe eine Erweiterungsmethode erstellt, die mehrere Vorschläge kombiniert:

  1. Illegale Zeichen in einem Hash-Set halten
  2. Zeichen unter ASCII 127 herausfiltern. Path.GetInvalidFileNameChars enthält nicht alle ungültigen Zeichen, die mit ASCII-Codes von 0 bis 255 möglich sind. Siehe hier und MSDN
  3. Möglichkeit zur Definition des Ersatzzeichens

Quelle:

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
schoetbi

Dies wird Sie wollen und Kollisionen vermeiden

 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
mcintyre321

Ich denke, die Frage wurde nicht vollständig beantwortet ....... Die Antworten beschreiben nur den Pfad des Dateinamens OR ... und nicht beides. Hier ist meine Lösung:

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
Suplanus