2009-10-23 16 views
59

jaki sposób można przekonwertować ten ciąg:przekonwertować ciąg Unicode zbiegłego ciąg znaków ASCII

This string contains the Unicode character Pi(π) 

do zbiegłego ciąg znaków ASCII:

This string contains the Unicode character Pi(\u03a0) 

i odwrotnie?

Obecne kodowanie dostępne w C# zamienia znak π na "?". Muszę zachować tę postać.

Odpowiedz

99

To idzie w tę iz powrotem do iz formatu \ uXXXX.

class Program { 
    static void Main(string[] args) { 
     string unicodeString = "This function contains a unicode character pi (\u03a0)"; 

     Console.WriteLine(unicodeString); 

     string encoded = EncodeNonAsciiCharacters(unicodeString); 
     Console.WriteLine(encoded); 

     string decoded = DecodeEncodedNonAsciiCharacters(encoded); 
     Console.WriteLine(decoded); 
    } 

    static string EncodeNonAsciiCharacters(string value) { 
     StringBuilder sb = new StringBuilder(); 
     foreach(char c in value) { 
      if(c > 127) { 
       // This character is too big for ASCII 
       string encodedValue = "\\u" + ((int) c).ToString("x4"); 
       sb.Append(encodedValue); 
      } 
      else { 
       sb.Append(c); 
      } 
     } 
     return sb.ToString(); 
    } 

    static string DecodeEncodedNonAsciiCharacters(string value) { 
     return Regex.Replace(
      value, 
      @"\\u(?<Value>[a-zA-Z0-9]{4})", 
      m => { 
       return ((char) int.Parse(m.Groups["Value"].Value, NumberStyles.HexNumber)).ToString(); 
      }); 
    } 
} 

Wyjścia:

Funkcja ta zawiera PI Unicode (n)

Funkcja ta zawiera PI Unicode (\ u03a0)

Funkcja ta zawiera PI Unicode (π)

+1

DecodeEncodedNonAsciiCharacters rzuci wyjątek FormatException dla ciągów takich jak "\\ użytkownik" – vovafeldman

+3

\ użytkownik nie powinien się dopasować, ponieważ po u, nie ma 4 znaków, ale dostaję twój punkt. Po prostu zmień dopasowanie do wyrażenia regularnego na [a-fA-F0-9]. Nadal będzie pasować do rzeczy, które nie pasują do siebie, ale wydaje się, że nadal pasuje do pierwotnego intencji pytania. –

+2

Wygląda ładnie i czysto. Mimo to jestem zaskoczony, że nie ma klasy System .Net, która to zrobi. – saarp

0

trzeba użyć metody Convert() w klasie Encoding:

  • Załóż Encoding obiekt reprezentujący kodowania ASCII
  • Załóż Encoding obiekt reprezentujący kodowania Unicode
  • połączenia Encoding.Convert() z kodowania źródłowego , kodowanie miejsca docelowego i ciąg do zakodowania

Jest przykładem here:

using System; 
using System.Text; 

namespace ConvertExample 
{ 
    class ConvertExampleClass 
    { 
     static void Main() 
     { 
     string unicodeString = "This string contains the unicode character Pi(\u03a0)"; 

     // Create two different encodings. 
     Encoding ascii = Encoding.ASCII; 
     Encoding unicode = Encoding.Unicode; 

     // Convert the string into a byte[]. 
     byte[] unicodeBytes = unicode.GetBytes(unicodeString); 

     // Perform the conversion from one encoding to the other. 
     byte[] asciiBytes = Encoding.Convert(unicode, ascii, unicodeBytes); 

     // Convert the new byte[] into a char[] and then into a string. 
     // This is a slightly different approach to converting to illustrate 
     // the use of GetCharCount/GetChars. 
     char[] asciiChars = new char[ascii.GetCharCount(asciiBytes, 0, asciiBytes.Length)]; 
     ascii.GetChars(asciiBytes, 0, asciiBytes.Length, asciiChars, 0); 
     string asciiString = new string(asciiChars); 

     // Display the strings created before and after the conversion. 
     Console.WriteLine("Original string: {0}", unicodeString); 
     Console.WriteLine("Ascii converted string: {0}", asciiString); 
     } 
    } 
} 
+3

Próbowałem to już. Problem z tym, że konwertuje znak Unicode π (\ u03a0) na "?". Potrzebuję go, aby przekonwertować go na "\ u03a0". – Ali

10
string StringFold(string input, Func<char, string> proc) 
{ 
    return string.Concat(input.Select(proc).ToArray()); 
} 

string FoldProc(char input) 
{ 
    if (input >= 128) 
    { 
    return string.Format(@"\u{0:x4}", (int)input); 
    } 
    return input.ToString(); 
} 

string EscapeToAscii(string input) 
{ 
    return StringFold(input, FoldProc); 
} 
+2

Wszystko, co nie obejmuje regex, ma mój głos. –

2
class Program 
{ 
     static void Main(string[] args) 
     { 
      char[] originalString = "This string contains the unicode character Pi(π)".ToCharArray(); 
      StringBuilder asAscii = new StringBuilder(); // store final ascii string and Unicode points 
      foreach (char c in originalString) 
      { 
       // test if char is ascii, otherwise convert to Unicode Code Point 
       int cint = Convert.ToInt32(c); 
       if (cint <= 127 && cint >= 0) 
        asAscii.Append(c); 
       else 
        asAscii.Append(String.Format("\\u{0:x4} ", cint).Trim()); 
      } 
      Console.WriteLine("Final string: {0}", asAscii); 
      Console.ReadKey(); 
     } 
} 

Wszystkie znaki spoza ASCII są konwertowane do ich reprezentacji kodu Unicode i dołączone do końcowego ciągu.

0

Aby zapisać rzeczywiste punkty kodowe Unicode, należy najpierw rozszyfrować kody kodu UTF-16 Stringa do kodów UTF-32 (które są obecnie takie same jak kody kodowe Unicode). Użyj do tego celu System.Text.Encoding.UTF32.GetBytes(), a następnie zapisz wynikowe bajty do StringBuilder w razie potrzeby, tj.

static void Main(string[] args) 
{ 
    String originalString = "This string contains the unicode character Pi(π)"; 
    Byte[] bytes = Encoding.UTF32.GetBytes(originalString); 
    StringBuilder asAscii = new StringBuilder(); 
    for (int idx = 0; idx < bytes.Length; idx += 4) 
    { 
     uint codepoint = BitConverter.ToUInt32(bytes, idx); 
     if (codepoint <= 127) 
      asAscii.Append(Convert.ToChar(codepoint)); 
     else 
      asAscii.AppendFormat("\\u{0:x4}", codepoint); 
    } 
    Console.WriteLine("Final string: {0}", asAscii); 
    Console.ReadKey(); 
} 
2

Mała poprawka do @Adam odpowiedź parapety, która rozwiązuje FormatException o przypadkach, w których ciąg wejściowy jak "C: \ u00ab \ otherdirectory \" Plus RegexOptions.Compiled czyni Regex kompilacja znacznie szybciej:

private static Regex DECODING_REGEX = new Regex(@"\\u(?<Value>[a-fA-F0-9]{4})", RegexOptions.Compiled); 
    private const string PLACEHOLDER = @"#!#"; 
    public static string DecodeEncodedNonAsciiCharacters(this string value) 
    { 
     return DECODING_REGEX.Replace(
      value.Replace(@"\\", PLACEHOLDER), 
      m => { 
       return ((char)int.Parse(m.Groups["Value"].Value, NumberStyles.HexNumber)).ToString(); }) 
      .Replace(PLACEHOLDER, @"\\"); 
    } 
3

w jednej wkładki:

var result = Regex.Replace(input, @"[^\x00-\x7F]", c => 
    string.Format(@"\u{0:x4}", (int)c.Value[0])); 
10

Dla cofanie zmiany można po prostu skorzystać z tej funkcji:

System.Text.RegularExpressions.Regex.Unescape(string) 

System.Uri.UnescapeDataString(string) 

Moim przy użyciu tej metody (To działa lepiej z UTF-8):

UnescapeDataString(string) 
1

Oto moja aktualna realizacja:

public static class UnicodeStringExtensions 
{ 
    public static string EncodeNonAsciiCharacters(this string value) { 
     var bytes = Encoding.Unicode.GetBytes(value); 
     var sb = StringBuilderCache.Acquire(value.Length); 
     bool encodedsomething = false; 
     for (int i = 0; i < bytes.Length; i += 2) { 
      var c = BitConverter.ToUInt16(bytes, i); 
      if ((c >= 0x20 && c <= 0x7f) || c == 0x0A || c == 0x0D) { 
       sb.Append((char) c); 
      } else { 
       sb.Append($"\\u{c:x4}"); 
       encodedsomething = true; 
      } 
     } 
     if (!encodedsomething) { 
      StringBuilderCache.Release(sb); 
      return value; 
     } 
     return StringBuilderCache.GetStringAndRelease(sb); 
    } 


    public static string DecodeEncodedNonAsciiCharacters(this string value) 
     => Regex.Replace(value,/*language=regexp*/@"(?:\\u[a-fA-F0-9]{4})+", Decode); 

    static readonly string[] Splitsequence = new [] { "\\u" }; 
    private static string Decode(Match m) { 
     var bytes = m.Value.Split(Splitsequence, StringSplitOptions.RemoveEmptyEntries) 
       .Select(s => ushort.Parse(s, NumberStyles.HexNumber)).SelectMany(BitConverter.GetBytes).ToArray(); 
     return Encoding.Unicode.GetString(bytes); 
    } 
} 

To przechodzi test:

public void TestBigUnicode() { 
    var s = "\U00020000"; 
    var encoded = s.EncodeNonAsciiCharacters(); 
    var decoded = encoded.DecodeEncodedNonAsciiCharacters(); 
    Assert.Equals(s, decoded); 
} 

z zakodowaną wartość: "\ud840\udc00"

Ta implementacja korzysta z (linku źródłowym odniesienia) StringBuilderCache

Powiązane problemy