Come rimuovere caratteri illegali dal percorso e dai nomi dei file?


456

Ho bisogno di un modo robusto e semplice per rimuovere percorsi e caratteri file illegali da una semplice stringa. Ho usato il codice qui sotto ma non sembra fare nulla, cosa mi sto perdendo?

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 rimuove i caratteri dall'inizio e dalla fine delle stringhe. Tuttavia, probabilmente dovresti chiederti perché i dati non sono validi e invece di provare a disinfettare / correggere i dati, respingili.
user7116,

8
I nomi in stile Unix non sono validi su Windows e non voglio occuparmi dei nomi abbreviati 8.3.
Gary Willoughby,

GetInvalidFileNameChars()toglierà cose come: \ etc dai percorsi delle cartelle.
Bloke CAD,

1
Path.GetInvalidPathChars()non sembra spogliarsi *o?
CAD bloke

19
Ho testato cinque risposte da questa domanda (ciclo programmato di 100.000) e il metodo seguente è il più veloce. L'espressione regolare ha preso il 2 ° posto ed era più lenta del 25%: stringa pubblica GetSafeFilename (string filename) {return string.Join ("_", filename.Split (Path.GetInvalidFileNameChars ())); }
Brain2000,

Risposte:


494

Prova qualcosa del genere invece;

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

Ma devo essere d'accordo con i commenti, probabilmente proverei a trattare la fonte dei percorsi illegali, piuttosto che cercare di trasformare un percorso illegale in un percorso legittimo ma probabilmente non intenzionale.

Modifica: O una soluzione potenzialmente "migliore", usando Regex's.

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

Tuttavia, la domanda si pone, perché in primo luogo lo stai facendo.


40
Non è necessario aggiungere le due liste insieme. L'elenco char del nome file illegale contiene l'elenco char del percorso illegale e ne ha alcuni di più. Ecco le liste di entrambe le liste espresse in 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 questo può essere vero su Windows e l'implementazione di Microsoft di .NET. Non sono disposto a fare lo stesso presupposto per dire mono con Linux in esecuzione.
Matthew Scharley,

7
Per quanto riguarda la prima soluzione. StringBuilder non dovrebbe essere più efficiente delle assegnazioni di stringhe?
epignosisx,

6
Per quello che vale, @MatthewScharley, l'implementazione Mono di GetInvalidPathChars () restituisce solo 0x00 e GetInvalidFileNameChars () restituisce solo 0x00 e '/' quando è in esecuzione su piattaforme non Windows. Su Windows, l'elenco di caratteri non validi è molto più lungo e GetInvalidPathChars () è interamente duplicato all'interno di GetInvalidFileNameChars (). Questo non cambierà nel prossimo futuro, quindi tutto ciò che stai realmente facendo è raddoppiare il tempo impiegato per eseguire questa funzione perché sei preoccupato che la definizione di un percorso valido cambierà presto. Che non lo farà.
Warren Rumak,

13
@Charleh questa discussione è così inutile ... il codice dovrebbe sempre essere ottimizzato e non c'è rischio che ciò sia errato. Anche un nome file fa parte del percorso. Quindi è solo illogico che GetInvalidPathChars()potrebbe contenere personaggi che GetInvalidFileNameChars()non lo sarebbero. Non stai prendendo la correttezza sull'ottimizzazione "prematura". Stai semplicemente usando un codice errato.
Stefan Fabian,

355

La domanda originale ha chiesto di "rimuovere i caratteri illegali":

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

Puoi invece sostituirli:

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

Questa risposta è stata su un altro thread di Cerere , mi piace davvero pulito e semplice.


10
Per rispondere precisamente alla domanda del PO, dovresti usare "" invece di "_", ma la tua risposta probabilmente si applica a più di noi in pratica. Penso che la sostituzione di personaggi illegali con alcuni legali sia fatta più comunemente.
BH,

37
Ho testato cinque metodi da questa domanda (loop temporizzato di 100.000) e questo metodo è il più veloce. L'espressione regolare ha preso il 2 ° posto ed era più lenta del 25% rispetto a questo metodo.
Brain2000,

10
Per rispondere al commento di @BH, si può semplicemente usare string.Concat (name.Split (Path.GetInvalidFileNameChars ()))
Michael Sutton,

210

Uso Linq per ripulire i nomi dei file. Puoi facilmente estenderlo per controllare anche i percorsi validi.

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

Aggiornare

Alcuni commenti indicano che questo metodo non funziona per loro, quindi ho incluso un collegamento a uno snippet DotNetFiddle in modo da poter convalidare il metodo.

https://dotnetfiddle.net/nw1SWY


4
Questo non ha funzionato per me. Il metodo non sta restituendo la stringa pulita. Restituisce il nome file passato così com'è.
Karan,

Quello che ha detto @Karan, questo non funziona, la stringa originale ritorna.
Jon

Si può effettivamente fare questo con LINQ come questo però: var invalid = new HashSet<char>(Path.GetInvalidPathChars()); return new string(originalString.Where(s => !invalid.Contains(s)).ToArray()). Le prestazioni probabilmente non sono eccezionali, ma probabilmente non importa.
Casey,

2
@Karan o Jon Che input stai inviando questa funzione? Vedi la mia modifica per la verifica di questo metodo.
Michael Minton,

3
È facile - i ragazzi stavano passando stringhe con caratteri validi. Eseguito l'upgrade per una soluzione aggregata interessante.
Nickmaovich,

89

Puoi rimuovere i caratteri illegali usando Linq in questo modo:

var invalidChars = Path.GetInvalidFileNameChars();

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

EDIT
Ecco come appare con la modifica richiesta menzionata nei commenti:

var invalidChars = Path.GetInvalidFileNameChars();

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

1
Mi piace in questo modo: mantieni solo i caratteri consentiti nella stringa (che non è altro che un array di caratteri).
Amico Pascalou,

6
So che questa è una vecchia domanda, ma questa è una risposta fantastica. Tuttavia, volevo aggiungere che in c # non è possibile eseguire il cast da char [] alla stringa in modo implicito o esplicito (pazzo, lo so), quindi è necessario rilasciarlo in un costruttore di stringhe.
JNYRanger,

1
Non l'ho confermato, ma mi aspetto che Path.GetInvalidPathChars () sia un superset di GetInvalidFileNameChars () e che copra sia i nomi dei file che i percorsi, quindi probabilmente lo userò invece.
angularsen,

3
@anjdreas attualmente Path.GetInvalidPathChars () sembra essere un sottoinsieme di Path.GetInvalidFileNameChars (), non viceversa. Path.GetInvalidPathChars () non restituirà '?', Ad esempio.
Rafael Costa,

1
Questa è una buona risposta Uso sia l'elenco dei nomi dei file sia l'elenco dei percorsi dei file: ____________________________ stringa cleanData = nuova stringa (data.Where (x =>! Path.GetInvalidFileNameChars (). Contiene (x) &&! Path.GetInvalidPathChars (). Contains (x)). ToArray ());
goamn

27

Queste sono tutte ottime soluzioni, ma fanno tutti affidamento Path.GetInvalidFileNameChars, che potrebbero non essere affidabili come si potrebbe pensare. Si noti la seguente osservazione nella documentazione MSDN su Path.GetInvalidFileNameChars:

Non è garantito che l' array restituito da questo metodo contenga l'insieme completo di caratteri non validi nei nomi di file e directory. Il set completo di caratteri non validi può variare in base al file system. Ad esempio, su piattaforme desktop basate su Windows, i caratteri di percorso non validi potrebbero includere caratteri ASCII / Unicode da 1 a 31, nonché virgolette ("), minore di (<), maggiore di (>), pipe (|), backspace ( \ b), null (\ 0) e tab (\ t).

Non è meglio con il Path.GetInvalidPathCharsmetodo. Contiene la stessa identica osservazione.


13
Allora qual è il punto di Path.GetInvalidFileNameChars? Mi aspetto che restituisca esattamente i caratteri non validi per il sistema corrente, facendo affidamento su .NET per sapere su quale filesystem sto correndo e presentandomi i caratteri non validi adatti. Se questo non è il caso e restituisce solo caratteri hardcoded, che non sono affidabili in primo luogo, questo metodo dovrebbe essere rimosso poiché ha valore zero.
Jan

1
So che questo è un vecchio commento ma, @Jan potresti voler scrivere su un altro filesystem, forse è per questo che c'è un avvertimento.
fantastik78,

3
@ fantastik78 buon punto, ma in questo caso vorrei avere un argomento enum aggiuntivo per specificare il mio FS remoto. Se questo è un eccessivo sforzo di manutenzione (che è il caso più probabile), l'intero metodo è ancora una cattiva idea, perché ti dà l'impressione sbagliata di sicurezza.
Jan

1
@Jan Sono totalmente d'accordo con te, stavo solo discutendo dell'avvertimento.
fantastik78,

È interessante notare che questa è una sorta di caratteri non validi "nella lista nera". Non sarebbe meglio "autorizzare" solo i caratteri validi conosciuti qui ?! Mi ricorda la stupida idea di "virusscanner" invece di autorizzare le applicazioni consentite ....
Bernhard

26

Per i nomi dei file:

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

Per percorsi completi:

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

Si noti che se si intende utilizzarlo come funzionalità di sicurezza, un approccio più solido sarebbe quello di espandere tutti i percorsi e quindi verificare che il percorso fornito dall'utente sia effettivamente figlio di una directory a cui l'utente dovrebbe avere accesso.


18

Per cominciare, Taglia rimuove solo i caratteri dall'inizio o dalla fine della stringa . In secondo luogo, dovresti valutare se desideri veramente rimuovere i caratteri offensivi o fallire velocemente e far sapere all'utente che il suo nome file non è valido. La mia scelta è quest'ultima, ma la mia risposta dovrebbe almeno mostrarti come fare le cose nel modo giusto E sbagliato:

StackOverflow domanda che mostra come verificare se una determinata stringa è un nome file valido . Nota che puoi usare la regex da questa domanda per rimuovere i caratteri con una sostituzione di espressioni regolari (se hai davvero bisogno di farlo).


Concordo in particolare con il secondo consiglio.
OregonGhost,

4
Normalmente concordo con il secondo, ma ho un programma che genera un nome file e che può contenere caratteri illegali in alcune situazioni. Dal momento che il mio programma sta generando nomi di file illegali, penso che sia appropriato rimuovere / sostituire quei caratteri. (Solo sottolineando un caso d'uso valido)
JDB ricorda ancora Monica

16

Il modo migliore per rimuovere il carattere illegale dall'input dell'utente è quello di sostituire il carattere illegale usando la classe Regex, creare un metodo nel codice dietro o anche validarlo sul lato client usando il controllo RegularExpression.

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

O

<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 questa soluzione è molto meglio di altre Invece di cercare tutti i caratteri non validi basta definire quali sono validi.
igorushi,

15

Uso espressioni regolari per raggiungere questo obiettivo. Innanzitutto, costruisco dinamicamente il regex.

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

Quindi chiamo removeInvalidChars.Replace per trovare e sostituire. Questo ovviamente può essere esteso anche ai caratteri del percorso.


Strano, ha funzionato per me. Lo ricontrollerò quando avrò la possibilità. Puoi essere più specifico e spiegare cosa non funziona esattamente per te?
Jeff Yates,

1
Non funzionerà (almeno correttamente) perché non stai sfuggendo correttamente ai caratteri del percorso e alcuni di essi hanno un significato speciale. Fare riferimento alla mia risposta per come farlo.
Matthew Scharley,

@Jeff: la tua versione è ancora migliore di quella di Matthew, se la modifichi leggermente. Fare riferimento alla mia risposta su come.
Jan

2
Vorrei anche aggiungere altri schemi di nomi di file non validi che possono essere trovati su MSDN ed estendere la soluzione al seguente regex: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

Preferisco assolutamente l'idea di Jeff Yates. Funzionerà perfettamente, se lo modifichi leggermente:

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

Il miglioramento è solo quello di sfuggire al regex generato automaticamente.


11

Ecco uno snippet di codice che dovrebbe essere utile per .NET 3 e versioni successive.

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

La maggior parte delle soluzioni sopra combinano caratteri non validi sia per il percorso che per il nome del file che è errato (anche quando entrambe le chiamate restituiscono lo stesso set di caratteri). Prima dividerei il percorso + nome file in percorso e nome file, quindi applicherei il set appropriato a entrambi e poi combinerei nuovamente i due.

wvd_vegt


+1: molto vero. Oggi, lavorando in .NET 4.0, la soluzione regex dalla risposta principale ha cancellato tutte le barre rovesciate in un percorso completo. Così ho creato una regex per il percorso dir e una regex solo per il nome file, pulita separatamente e ricombinata
dario_ramos

Potrebbe essere vero, ma questo non risponde alla domanda. Non sono sicuro che un vago "lo farei così" sia di grandissimo aiuto rispetto ad alcune delle soluzioni complete già qui (vedi ad esempio la risposta di Lilly, di seguito)
Ian Grainger,

6

Se rimuovi o sostituisci con un singolo carattere i caratteri non validi, puoi avere collisioni:

<abc -> abc
>abc -> abc

Ecco un metodo semplice per evitare questo:

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

Il risultato:

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

5

Lancia un'eccezione.

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

4

Ho scritto questo mostro per divertimento, ti consente di andata e ritorno:

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
Mi piace perché evita di avere due stringhe diverse creando lo stesso percorso risultante.
Kim,

3

Penso che sia molto più facile convalidare usando una regex e specificare quali caratteri sono consentiti, invece di cercare di controllare tutti i personaggi cattivi. Vedi questi link: http://www.c-sharpcorner.com/UploadFile/prasad_1/RegExpPSD12062005021717AM/RegExpPSD.aspx http://www.windowsdevcenter.com/pub/a/oreilly/windows/news/csharp_0101.html

Inoltre, fai una ricerca per "editor di espressioni regolari", che aiutano molto. Ce ne sono alcuni in giro che producono anche il codice in c # per te.


Dato che .net è un framework destinato a consentire l'esecuzione di programmi su più piattaforme (ad es. Linux / Unix e Windows), ritengo che Path.GetInvalidFileNameChars () sia il migliore poiché conterrà la conoscenza di ciò che è o non è ' t valido sul filesystem su cui è in esecuzione il programma. Anche se il tuo programma non verrà mai eseguito su Linux (forse è pieno di codice WPF), c'è sempre la possibilità che alcuni nuovi filesystem di Windows arrivino in futuro e abbiano caratteri diversi validi / non validi. Arrotolare il tuo con regex significa reinventare la ruota e spostare un problema di piattaforma nel tuo codice.
Daniel Scott,

Sono d'accordo con i tuoi consigli sugli editor / tester regex online. Li trovo inestimabili (dal momento che le regex sono cose difficili e piene di sottigliezza che possono farti inciampare facilmente, dandoti una regex che si comporta in un modo selvaggiamente inaspettato con casi limite). Il mio preferito è regex101.com (mi piace come si rompe la regex e ti mostra chiaramente cosa si aspetta corrisponda). Mi piace anche molto debuggex.com in quanto ha una rappresentazione visiva compatta di gruppi di match e classi di personaggi e quant'altro.
Daniel Scott,

3

Questo sembra essere O (n) e non spende troppa memoria sulle stringhe:

    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
Non penso che sia O (n) quando si utilizza la funzione 'Qualsiasi'.
II FRECCE

@IIARROWS e secondo te?
Alexey F,

Non lo so, non mi è sembrato così quando ho scritto il mio commento ... ora che ho provato a calcolarlo, sembra che tu abbia ragione.
II FRECCE

Ho selezionato questo per la tua considerazione sulla performance. Grazie.
Berend Engelbrecht,

3

Scansionando le risposte qui, tutti ** sembrano comportare l'utilizzo di un array di caratteri di nomi di file non validi.

Certo, questo potrebbe essere un micro-ottimizzazione, ma a beneficio di chiunque stia cercando di controllare un gran numero di valori per essere nomi di file validi, vale la pena notare che la creazione di un hashset di caratteri non validi porterà a prestazioni notevolmente migliori.

In passato sono stato molto sorpreso (scioccato) dalla rapidità con cui un hashset (o dizionario) supera le prestazioni di una lista. Con le stringhe, è un numero ridicolmente basso (circa 5-7 voci dalla memoria). Con la maggior parte degli altri dati semplici (riferimenti a oggetti, numeri, ecc.) Il crossover magico sembra essere di circa 20 elementi.

Esistono 40 caratteri non validi nella "lista" Path.InvalidFileNameChars. Ho fatto una ricerca oggi e c'è un buon punto di riferimento qui su StackOverflow che mostra che l'hashset impiegherà poco più della metà del tempo di un array / elenco per 40 elementi: https://stackoverflow.com/a/10762995/949129

Ecco la classe di supporto che utilizzo per i percorsi di disinfezione. Ora dimentico perché avevo l'opzione di sostituzione fantasia, ma è lì come un bonus carino.

Metodo bonus aggiuntivo "IsValidLocalPath" anche :)

(** quelli che non usano espressioni regolari)

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

Puoi usare il metodo chiaramente.


2

Il nome del file non può contenere personaggi Path.GetInvalidPathChars(), +e #simboli, e altri nomi specifici. Abbiamo unito tutti i controlli in una classe:

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

Il metodo GetValidFileNamesostituisce tutti i dati errati in _.


2

Un liner per pulire la stringa da qualsiasi carattere illegale per la denominazione dei file di 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

Questo vorrà che tu voglia ed evitare le collisioni

 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

Penso che la domanda non abbia già una risposta completa ... Le risposte descrivono solo il nome del file pulito o il percorso ... non entrambi. Ecco la mia soluzione:

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

Ho creato un metodo di estensione che combina diversi suggerimenti:

  1. Contiene personaggi illegali in un set di hash
  2. Filtraggio dei caratteri sotto ascii 127. Poiché Path.GetInvalidFileNameChars non include tutti i caratteri non validi possibili con codici ascii da 0 a 255. Vedi qui e MSDN
  3. Possibilità di definire il carattere sostitutivo

Fonte:

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

Ecco una funzione che sostituisce tutti i caratteri illegali in un nome file con un carattere sostitutivo:

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

Ad esempio, il carattere di sottolineatura può essere utilizzato come carattere sostitutivo:

NewFileName = ReplaceIllegalFileChars(FileName, '_');

Oltre alla risposta fornita, ti consigliamo di fornire una breve spiegazione del perché e di come risolvere il problema.
jtate

-7

Oppure puoi semplicemente farlo

[YOUR STRING].Replace('\\', ' ').Replace('/', ' ').Replace('"', ' ').Replace('*', ' ').Replace(':', ' ').Replace('?', ' ').Replace('<', ' ').Replace('>', ' ').Replace('|', ' ').Trim();
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.