2009-03-06 6 views

Antwort

120

versuchen, etwas wie folgt aus:

string fileName = "something"; 
foreach (char c in System.IO.Path.GetInvalidFileNameChars()) 
{ 
    fileName = fileName.Replace(c, '_'); 
} 

Edit:

Seit GetInvalidFileNameChars() wird 10 oder 15 Zeichen zurückgeben, ist es besser, einen StringBuilder anstelle einer einfachen Zeichenfolge zu verwenden; Die ursprüngliche Version dauert länger und verbraucht mehr Speicher.

+0

Guten Ruf auf S.I.P.GIFNC. Die Schleife ist in etwa das, was ich getan habe, aber ich bin nicht verrückt nach String zu nennen. Ersetze es in einer Schleife - ich hatte gehofft, dass es ein Built-in geben würde, das sowohl einfach * als auch * effizient ist. – Ken

+1

Sie könnten einen StringBuilder verwenden, wenn Sie möchten, aber wenn die Namen kurz sind und ich denke, es ist es nicht wert. Sie können auch eine eigene Methode erstellen, um ein char [] zu erstellen und alle falschen Zeichen in einer Iteration zu ersetzen. Immer ist es besser, es einfach zu halten, es sei denn, es funktioniert nicht, haben Sie möglicherweise schlimmere Engpässe –

+0

Ich weiß nicht C#, aber ist es nicht möglich, eine remove() -Methode zu verwenden, die eine Reihe von Zeichen nimmt? Diese Zeichenmenge scheint praktisch von GetInvalidFileNameChars() bereitgestellt zu werden. Auch, realistisch, wie oft wird diese Schleife iterieren? 6 normalerweise, höchstens 40, wenn die Fnuction auch nicht gedruckte ASCII zurückgibt, vielleicht? caveat: die msdn für diese Funktion erwähnt auch, dass Sie GetInvalidPathChars verwenden sollten, da GIFNC kein '\' oder '/' zurückgibt, was ungültige Dateinamen sind. – Pod

27
fileName = fileName.Replace(":", "-") 

Allerdings ist ":" nicht das einzige unzulässige Zeichen für Windows. Sie müssen auch behandeln:

/, \, :, *, ?, ", <, > and | 

Diese in System.IO.Path.GetInvalidFileNameChars enthalten sind();

Auch (unter Windows), "." kann nicht das einzige Zeichen im Dateinamen sein (sowohl ".", "..", "...", usw. sind ungültig). Seien Sie vorsichtig beim Benennen von Dateien mit, zum Beispiel „‚:

echo "test" > .test. 

eine Datei erzeugen namens‘.test“

Schließlich, wenn Sie wirklich wollen die Dinge richtig zu tun, gibt es einige special file names Sie müssen aufpassen. Unter Windows können Sie keine Dateien mit dem Namen erstellen:

CON, PRN, AUX, CLOCK$, NUL 
COM0, COM1, COM2, COM3, COM4, COM5, COM6, COM7, COM8, COM9 
LPT0, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, and LPT9. 
+2

Ich wusste nie über die reservierten Namen. Sinn macht auch –

+4

Auch, was es wert ist, können Sie keinen Dateinamen erstellen, der mit einem dieser reservierten Namen beginnt, gefolgt von einer Dezimalzahl. d. h. con.air.avi –

+0

".foo" ist ein gültiger Dateiname. Wusste nicht über den "CON" -Dateinamen - wozu dient er? – configurator

6

Diego hat die richtige Lösung, aber es gibt einen sehr kleinen Fehler drin. Die verwendete Version von string.Replace sollte string sein.Replace (char, char), es gibt keine Zeichenkette.Replace (Zeichenkette, Zeichenkette)

Ich kann die Antwort nicht bearbeiten oder ich hätte sie einfach gemacht kleine Veränderung.

So soll es sein:

string fileName = "something"; 
foreach (char c in System.IO.Path.GetInvalidFileNameChars()) 
{ 
    fileName = fileName.Replace(c, '_'); 
} 
-2

Sie dies mit einem sed Befehl tun können:

sed -e " 
s/[?()\[\]=+<>:;©®”,*|]/_/g 
s/"$'\t'"/ /g 
s/–/-/g 
s/\"/_/g 
s/[[:cntrl:]]/_/g" 
+0

siehe auch eine kompliziertere aber verwandte Frage an: http://stackoverflow.com/questions/4413427/automated-renaming-of-linux- filename-to-a-new-filenames-das-sind-legal-in-window –

+4

sed in C#, wirklich? –

+0

Warum muss dies in C# statt Bash getan werden? Ich sehe jetzt ein C# -Tag auf der ursprünglichen Frage, aber warum? –

10

Dies ist nicht effizienter, aber es ist mehr Spaß :)

var fileName = "foo:bar"; 
    var invalidChars = System.IO.Path.GetInvalidFileNameChars(); 
    var cleanFileName = new string(fileName.Where(m => !invalidChars.Contains(m)).ToArray<char>()); 
0

Ich musste dies heute tun ... in meinem Fall musste ich einen Kundennamen mit dem Datum und der Uhrzeit für eine endgültige .kmz-Datei verketten . Meine letzte Lösung war:

string name = "Whatever name with valid/invalid chars"; 
char[] invalid = System.IO.Path.GetInvalidFileNameChars(); 
string validFileName = string.Join(string.Empty, 
          string.Format("{0}.{1:G}.kmz", name, DateTime.Now) 
          .ToCharArray().Select(o => o.In(invalid) ? '_' : o)); 

Sie es sogar Räume ersetzen machen können, wenn Sie den Raum char auf den ungültigen Array hinzuzufügen.

Vielleicht ist es nicht der schnellste, aber da Leistung kein Problem war, fand ich es elegant und verständlich.

Prost!

1

ein wenig meinen Code Reinigung und ein wenig Refactoring machen ... habe ich eine Erweiterung für String-Typ:

public static string ToValidFileName(this string s, char replaceChar = '_', char[] includeChars = null) 
{ 
    var invalid = Path.GetInvalidFileNameChars(); 
    if (includeChars != null) invalid = invalid.Union(includeChars).ToArray(); 
    return string.Join(string.Empty, s.ToCharArray().Select(o => o.In(invalid) ? replaceChar : o)); 
} 

Jetzt ist es einfacher zu bedienen mit:

var name = "Any string you want using ?/\ or even +.zip"; 
var validFileName = name.ToValidFileName(); 

Wenn Sie möchten, ersetzen mit einem anderen Zeichen als „_“ Sie verwenden können:

var validFileName = name.ToValidFileName(replaceChar:'#'); 

Und Sie können Zeichen hinzufügen zu ersetzen .. fo r Beispiel müssen Sie nicht wollen, Leerzeichen oder Komma:

var validFileName = name.ToValidFileName(includeChars: new [] { ' ', ',' }); 

Hoffe, es hilft ...

Prost

5

Hier ist eine leichte Drehung auf Diegos Antwort.

Wenn Sie keine Angst vor Unicode haben, können Sie ein wenig mehr Genauigkeit bewahren, indem Sie die ungültigen Zeichen durch gültige Unicode-Symbole ersetzen, die ihnen ähneln. Hier ist der Code, den ich kürzlich in einem Projekt verwendete Bauholz Schnittlisten beteiligt: ​​

static string MakeValidFilename(string text) { 
    text = text.Replace('\'', '’'); // U+2019 right single quotation mark 
    text = text.Replace('"', '”'); // U+201D right double quotation mark 
    text = text.Replace('/', '⁄'); // U+2044 fraction slash 
    foreach (char c in System.IO.Path.GetInvalidFileNameChars()) { 
    text = text.Replace(c, '_'); 
    } 
    return text; 
} 

Dies erzeugt Dateinamen wie 1⁄2” spruce.txt statt 1_2_ spruce.txt

Ja, es funktioniert wirklich:

Explorer sample

Caveat Emptor

Ich kannte diesen Trick wo Er arbeitet mit NTFS, war aber überrascht, dass er auch auf FAT- und FAT32-Partitionen funktioniert. Das liegt daran, long filenames sind stored in Unicode, sogar as far back als Windows 95/NT. Ich habe auf Win7, XP und sogar einem Linux-basierten Router getestet und sie zeigten sich OK. Kann nicht dasselbe in einer DOSBox sagen.

Das heißt, bevor Sie mit diesem Thema gehen, überlegen Sie, ob Sie wirklich die zusätzliche Genauigkeit benötigen. Die Unicode-Ähnlichkeiten könnten Personen oder alte Programme, z. ältere Betriebssysteme verlassen sich auf codepages.

6

Falls jemand eine optimierte Version basierend auf StringBuilder möchte, verwenden Sie diese. Schließt rkagerers Trick als eine Option ein.

static char[] _invalids; 

/// <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 simply remove bad characters.</param> 
/// <param name="fancy">Whether 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, returns "_".</returns> 
public static string MakeValidFileName(string text, char? replacement = '_', bool fancy = true) 
{ 
    StringBuilder sb = new StringBuilder(text.Length); 
    var invalids = _invalids ?? (_invalids = Path.GetInvalidFileNameChars()); 
    bool changed = false; 
    for (int i = 0; i < text.Length; i++) { 
     char c = text[i]; 
     if (invalids.Contains(c)) { 
      changed = true; 
      var repl = replacement ?? '\0'; 
      if (fancy) { 
       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; 
} 
+0

+1 für schönen und lesbaren Code. Lässt die Bugs sehr leicht lesen und bemerken: P .. Diese Funktion sollte immer die ursprüngliche Zeichenkette zurückgeben, da die Änderung niemals wahr ist. –

+0

Danke, ich denke es ist jetzt besser. Sie wissen, was sie über Open Source sagen, "viele Augen machen alle Fehler oberflächlich, so dass ich keine Komponententests schreiben muss" ... – Qwertie

2

Hier ist eine Version, die StringBuilder und IndexOfAny mit Masse anhängen für volle Effizienz verwendet. Es gibt auch die ursprüngliche Zeichenfolge zurück, anstatt eine doppelte Zeichenfolge zu erstellen.

Last but not least, es hat eine switch-Anweisung, die Look-Alike-Zeichen zurückgibt, die Sie beliebig anpassen können. Schauen Sie sich Unicode.org's confusables lookup an, um zu sehen, welche Optionen Sie haben, abhängig von der Schriftart.

public static string GetSafeFilename(string arbitraryString) 
{ 
    var invalidChars = System.IO.Path.GetInvalidFileNameChars(); 
    var replaceIndex = arbitraryString.IndexOfAny(invalidChars, 0); 
    if (replaceIndex == -1) return arbitraryString; 

    var r = new StringBuilder(); 
    var i = 0; 

    do 
    { 
     r.Append(arbitraryString, i, replaceIndex - i); 

     switch (arbitraryString[replaceIndex]) 
     { 
      case '"': 
       r.Append("''"); 
       break; 
      case '<': 
       r.Append('\u02c2'); // '˂' (modifier letter left arrowhead) 
       break; 
      case '>': 
       r.Append('\u02c3'); // '˃' (modifier letter right arrowhead) 
       break; 
      case '|': 
       r.Append('\u2223'); // '∣' (divides) 
       break; 
      case ':': 
       r.Append('-'); 
       break; 
      case '*': 
       r.Append('\u2217'); // '∗' (asterisk operator) 
       break; 
      case '\\': 
      case '/': 
       r.Append('\u2044'); // '⁄' (fraction slash) 
       break; 
      case '\0': 
      case '\f': 
      case '?': 
       break; 
      case '\t': 
      case '\n': 
      case '\r': 
      case '\v': 
       r.Append(' '); 
       break; 
      default: 
       r.Append('_'); 
       break; 
     } 

     i = replaceIndex + 1; 
     replaceIndex = arbitraryString.IndexOfAny(invalidChars, i); 
    } while (replaceIndex != -1); 

    r.Append(arbitraryString, i, arbitraryString.Length - i); 

    return r.ToString(); 
} 

Es sucht nicht nach ., .. oder reservierten Namen wie CON, weil nicht klar ist, was sollte der Ersatz sein.

1

Hier ist eine Version der akzeptierte Antwort mit Linq die Enumerable.Aggregate verwendet:

string fileName = "something"; 

Path.GetInvalidFileNameChars() 
    .Aggregate(fileName, (current, c) => current.Replace(c, '_')); 
1

Eine weitere einfache Lösung:

private string MakeValidFileName(string original, char replacementChar = '_') 
{ 
    var invalidChars = new HashSet<char>(Path.GetInvalidFileNameChars()); 
    return new string(original.Select(c => invalidChars.Contains(c) ? replacementChar : c).ToArray()); 
} 
Verwandte Themen