Frage

Ich brauche eine robuste und einfache Art und Weise illegal Pfad und Datei Zeichen aus einem einfachen String zu entfernen. Ich habe den Code unten verwendet, aber es scheint nicht, etwas zu tun, was bin ich dabei?

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();
        }
    }
}
War es hilfreich?

Lösung

Versuchen Sie so etwas wie dies statt;

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 habe mit den Kommentaren zustimmen, würde ich wahrscheinlich versuchen, mit der Quelle der illegalen Wege zu beschäftigen, anstatt zu versuchen, einen illegalen Weges in einen legitimen, aber wahrscheinlich unbeabsichtigt einen mangle.

Edit:. Oder eine potenziell 'bessere' Lösung, mit Regex des

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 gestellt werden, warum diese in erster Linie tun.

Andere Tipps

public string GetSafeFilename(string filename)
{

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

}

Diese Antwort war auf einem anderen Thread von Ceres , Ich mag es sauber und einfach.

Ich verwende Linq Dateinamen zu bereinigen. Sie können dies leicht erweitern als auch für gültige Pfade zu überprüfen.

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

Update

Einige Kommentare zeigen diese Methode nicht für sie arbeiten, also habe ich einen Link zu einer DotNetFiddle Schnipsel enthalten, so dass Sie die Methode validieren können.

https://dotnetfiddle.net/nw1SWY

Sie können illegale Zeichen entfernen Linq verwenden wie folgt aus:

var invalidChars = Path.GetInvalidFileNameChars();

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

Bearbeiten
Dies ist, wie es mit den erforderlichen Bearbeitungs sieht in den Kommentaren erwähnt:

var invalidChars = Path.GetInvalidFileNameChars();

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

Dies alles sind große Lösungen, aber sie alle verlassen sich auf Path.GetInvalidFileNameChars, die nicht so zuverlässig sein, wie Sie denken. Beachten Sie die folgende Bemerkung in der MSDN-Dokumentation auf Path.GetInvalidFileNameChars :

  

Das Array von dieser Methode zurückgegeben wird, ist nicht garantierte den vollständigen Satz von Zeichen enthalten, die in Datei- und Verzeichnisnamen ungültig sind. Der vollständige Satz von ungültigen Zeichen von Dateisystem variieren. (|) Beispielsweise auf Windows-basierten Desktop-Plattformen, ungültiger Pfad Zeichen könnten ASCII / Unicode-Zeichen 1 bis 31 sowie Anführungszeichen ( "), kleiner als (<), größer als (>), Rohr umfassen, Backspace ( \ b), null (\ 0) und Tabulator (\ t).

Es ist nicht besser mit Path.GetInvalidPathChars Methode. Es enthält genau die gleiche Bemerkung.

Für Dateinamen:

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

Für die vollständigen Pfade:

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

Beachten Sie, wenn Sie beabsichtigen, diese als Sicherheitsmerkmal zu verwenden, wird ein robusterer Ansatz alle Pfade erweitern würde und dann überprüfen, ob der Benutzer bereitgestellte Pfad ist in der Tat ein Kind eines Verzeichnisses der Benutzer Zugriff haben soll.

Für den Anfang Trim entfernt nur Zeichen von Anfang an oder Ende der Zeichenfolge . Zweitens sollten Sie beurteilen, ob Sie wirklich die Offensive Zeichen entfernen mögen, oder schnell scheitern und lassen die Benutzer wissen, dass ihr Dateiname ungültig ist. Meine Wahl ist die letztere, aber meine Antwort soll man zumindest zeigen, wie die Dinge tun, um den richtigen und falschen Weg:

Frage Stackoverflow zeigt, wie man überprüfen, ob eine bestimmte Zeichenfolge ein gültiger Dateiname ist. Beachten Sie die Regex von dieser Frage verwenden können, um Zeichen mit einem regulären Ausdruck Ersatz zu entfernen (wenn Sie dies wirklich tun müssen, um).

Ich benutze reguläre Ausdrücke, dies zu erreichen. Zuerst habe ich dynamisch die regex bauen.

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 removeInvalidChars.Replace nur den Fund zu tun und zu ersetzen. Dies kann natürlich erweitert werden, um Pfad Zeichen als auch abdecken.

Der beste Weg, unzulässige Zeichen von Benutzereingaben zu entfernen, ist illegal Zeichen mit Regex-Klasse zu ersetzen, create-Methode in Code hinter oder auf Client-Seite mit RegulaererAusdruck Steuerung auch validieren.

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

Ich ziehe es absolut die Idee von Jeff Yates. Es wird perfekt funktionieren, wenn Sie es etwas ä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 ist nur die automaticially erzeugt regex zu entkommen.

Hier ist ein Code-Schnipsel, die für .NET 3 und höher helfen sollen.

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

Die meisten Lösungen, die oben kombinieren illegale Zeichen für beide Pfad und Dateinamen, die falsch ist (auch wenn beide Anrufe zur Zeit den gleichen Satz von Zeichen zurück). Ich würde geteilt zuerst den Pfad + Dateinamen in Pfad und Dateinamen, dann wenden Sie den entsprechenden Satz entweder, wenn sie und dann die beiden wieder verbinden.

wvd_vegt

Wenn Sie die ungültigen Zeichen mit einem einzelnen Zeichen entfernen oder ersetzen, können Sie Kollisionen haben:

<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

eine Ausnahme aus.

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

ich dieses Monster zum Spaß geschrieben, es läßt Dich Rundreise:

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

Ich denke, dass es viel einfacher ist, einen regulären Ausdruck und specifiing zur Validierung verwendet, die Zeichen sind erlaubt, anstatt zu versuchen, für alle schlechten Zeichen zu überprüfen. Sehen Sie diese Links: http://www.c-sharpcorner.com/UploadFile/prasad_1/ RegExpPSD12062005021717AM / RegExpPSD.aspx http://www.windowsdevcenter.com/pub/a/ oreilly / windows / news / csharp_0101.html

Auch eine Suche nach „Editor für reguläre Ausdrücke“ s, helfen sie viel. Es gibt einige, um die sich sogar Ausgabe der Code in C # für Sie.

Das scheint O (n) und nicht verbringen zu viel Speicher auf Strings zu sein:

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

Scannen über die Antworten hier, sie alle ** scheinen einen char-Array von ungültigen Dateinamen Zeichen einbeziehen verwenden.

Zugegeben, kann diese Mikro-Optimierung - aber zum Wohl eines jeden, der für gültig Dateinamen, eine große Anzahl von Werten zu überprüfen könnte suchen, ist es erwähnenswert, dass ein Hashset von ungültigen Zeichen Gebäude wird über deutlich bessere Leistung bringen .

Ich habe sehr überrascht (schockiert) in der Vergangenheit, wie schnell ein Hashset (oder Wörterbuch) Iterieren über eine Liste trifft. Mit Streichern, dann ist es eine lächerlich geringe Anzahl (ca. 5-7 Artikel aus dem Gedächtnis). Bei den meisten anderen einfachen Daten (Objektreferenzen, Zahlen usw.) die magische Crossover scheint sich um 20 Elemente zu sein.

Es gibt 40 ungültige Zeichen in der Path.InvalidFileNameChars "Liste". Hätte eine Suche heute und es ist schon ein guter Maßstab hier auf Stackoverflow, der den Hashset zeigt für 40 Artikel etwas mehr als die Hälfte der Zeit eines Arrays / Liste nehmen: https://stackoverflow.com/a/10762995/949129

Hier ist die Helferklasse I für desinfizierende Pfade verwenden. Hab 'ich vergessen, warum ich die Phantasie Ersatz Option drin hatte, aber es ist dort als netter Bonus.

Zusätzliche Bonus-Methode "IsValidLocalPath" too:)

(** solche, die reguläre Ausdrücke nicht 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;
    }
}
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.

Dateiname darf keine Zeichen von Path.GetInvalidPathChars(), + und # Symbolen und anderen spezifischen Namen. Wir kombiniert alle Prüfungen in einer Klasse:

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

Methode GetValidFileName ersetzt alle fehlerhaften Daten _.

Ein Liner Bereinigungs Zeichenfolge von illegalen Zeichen für Fenster Dateibenennung:

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

Dies wird wollen Sie wollen, und vermeiden Sie Kollisionen

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

    }

Ich denke, die Frage noch nicht vollständig beantwortet ... Die Antworten beschreiben nur sauberen Dateinamen oder Pfad ... nicht beide. 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;
}

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

  1. Halten Sie ungültige Zeichen in einem Hash-Set
  2. Zeichen unter ascii Ausfiltern 127. Da Path.GetInvalidFileNameChars enthält nicht alle ungültigen Zeichen möglich mit ASCII-Codes von 0 bis 255 sehen Sie hier und MSDN
  3. Possiblity die Ersatzzeichen
  4. zu definieren,

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

Oder Sie können einfach tun

[YOUR STRING].Replace('\\', ' ').Replace('/', ' ').Replace('"', ' ').Replace('*', ' ').Replace(':', ' ').Replace('?', ' ').Replace('<', ' ').Replace('>', ' ').Replace('|', ' ').Trim();
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top