2012-06-14 2 views
7

Ich versuche, zwei Funktionen escape(text, delimiter) und unescape(text, delimiter) mit den folgenden Eigenschaften zu schreiben:Was ist der einfachste Algorithmus, um ein einzelnes Zeichen zu entkommen?

  1. Das Ergebnis escape nicht delimiter enthält.

  2. unescape ist die Umkehrung der escape, das heißt

    unescape(escape(text, delimiter), delimiter) == text 
    

    für alle Werte von text und delimiter

Es ist OK, um die zulässigen Werte von delimiter zu beschränken.


Hintergrund: Ich möchte ein Trennzeichen getrennte Zeichenfolge von Werten erstellen. Um die gleiche Liste wieder aus der Zeichenfolge extrahieren zu können, muss ich sicherstellen, dass die einzelnen, getrennten Zeichenfolgen das Trennzeichen nicht enthalten.


Was ich versucht: ich mit einer einfachen Lösung (Pseudo-Code) kam:

escape(text, delimiter): return text.Replace("\", "\\").Replace(delimiter, "\d") 
unescape(text, delimiter): return text.Replace("\d", delimiter).Replace("\\", "\") 

aber entdeckt, dass Eigenschaft 2 "\d<delimiter>" auf dem Test-String ist fehlgeschlagen. Derzeit habe ich folgende Arbeitslösung

escape(text, delimiter): return text.Replace("\", "\b").Replace(delimiter, "\d") 
unescape(text, delimiter): return text.Replace("\d", delimiter).Replace("\b", "\") 

, die, so lange zu arbeiten scheint, als delimiter ist nicht \, b oder d (was in Ordnung ist, will ich nicht sowieso diejenigen, die als Trennzeichen verwenden). Da ich seine Richtigkeit jedoch nicht formal bewiesen habe, befürchte ich, dass ich einige Fälle übersehen habe, in denen eine der Eigenschaften verletzt wurde. Da dies ein so häufiges Problem ist, gehe ich davon aus, dass es bereits einen "altbewährten" Algorithmus gibt, daher meine Frage (siehe Titel).

+2

Escaping? Zuverlässig, einfach und schnell? Lol. – Will

+1

Was ist das Problem mit zuverlässiger, einfacher und schneller Flucht? –

Antwort

3

Ihr erster Algorithmus ist korrekt.

Der Fehler ist bei der Umsetzung der unescape(): Sie beide \d von delimiter und \\ von \, in einem Durchgang ersetzen müssen. Sie können nicht mehrere Aufrufe von Replace() wie folgt verwenden.

Hier einige Beispiele-C# -Code für eine sichere Angabe von Trennzeichen getrennten Zeichenkette:

static string QuoteSeparator(string str, 
     char separator, char quoteChar, char otherChar) // "~" -> "~~"  ";" -> "~s" 
    { 
     var sb = new StringBuilder(str.Length); 
     foreach (char c in str) 
     { 
      if (c == quoteChar) 
      { 
       sb.Append(quoteChar); 
       sb.Append(quoteChar); 
      } 
      else if (c == separator) 
      { 
       sb.Append(quoteChar); 
       sb.Append(otherChar); 
      } 
      else 
      { 
       sb.Append(c); 
      } 
     } 
     return sb.ToString(); // no separator in the result -> Join/Split is safe 
    } 
    static string UnquoteSeparator(string str, 
     char separator, char quoteChar, char otherChar) // "~~" -> "~"  "~s" -> ";" 
    { 
     var sb = new StringBuilder(str.Length); 
     bool isQuoted = false; 
     foreach (char c in str) 
     { 
      if (isQuoted) 
      { 
       if (c == otherChar) 
        sb.Append(separator); 
       else 
        sb.Append(c); 
       isQuoted = false; 
      } 
      else 
      { 
       if (c == quoteChar) 
        isQuoted = true; 
       else 
        sb.Append(c); 
      } 
     } 
     if (isQuoted) 
      throw new ArgumentException("input string is not correctly quoted"); 
     return sb.ToString(); // ";" are restored 
    } 

    /// <summary> 
    /// Encodes the given strings as a single string. 
    /// </summary> 
    /// <param name="input">The strings.</param> 
    /// <param name="separator">The separator.</param> 
    /// <param name="quoteChar">The quote char.</param> 
    /// <param name="otherChar">The other char.</param> 
    /// <returns></returns> 
    public static string QuoteAndJoin(this IEnumerable<string> input, 
     char separator = ';', char quoteChar = '~', char otherChar = 's') 
    { 
     CommonHelper.CheckNullReference(input, "input"); 
     if (separator == quoteChar || quoteChar == otherChar || separator == otherChar) 
      throw new ArgumentException("cannot quote: ambiguous format"); 
     return string.Join(new string(separator, 1), (from str in input select QuoteSeparator(str, separator, quoteChar, otherChar)).ToArray()); 
    } 

    /// <summary> 
    /// Decodes the strings encoded in a single string. 
    /// </summary> 
    /// <param name="encoded">The encoded.</param> 
    /// <param name="separator">The separator.</param> 
    /// <param name="quoteChar">The quote char.</param> 
    /// <param name="otherChar">The other char.</param> 
    /// <returns></returns> 
    public static IEnumerable<string> SplitAndUnquote(this string encoded, 
     char separator = ';', char quoteChar = '~', char otherChar = 's') 
    { 
     CommonHelper.CheckNullReference(encoded, "encoded"); 
     if (separator == quoteChar || quoteChar == otherChar || separator == otherChar) 
      throw new ArgumentException("cannot unquote: ambiguous format"); 
     return from s in encoded.Split(separator) select UnquoteSeparator(s, separator, quoteChar, otherChar); 
    } 
0

Vielleicht können Sie einen alternativen Ersatz für den Fall, wenn der Begrenzer tut Start mit \, b oder d. Verwenden Sie den gleichen alternativen Ersatz im unescape Algorithmus sowie

Verwandte Themen