将Unicode字符串转换为转义的ASCII字符串


77

如何转换此字符串:

This string contains the Unicode character Pi(π)

转换为转义的ASCII字符串:

This string contains the Unicode character Pi(\u03a0)

反之亦然

C#中当前可用的编码将π字符转换为“?”。我需要保留那个角色。

Answers:


135

这往返于\ 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();
            } );
    }
}

输出:

此函数包含一个Unicode字符pi(π)

此函数包含一个Unicode字符pi(\ u03a0)

此函数包含一个Unicode字符pi(π)


1
DecodeEncodedNonAsciiCharacters将为诸如“ \\ user”之类的字符串引发FormatException
vovafeldman 2012年

3
\ user不应该匹配,因为u后面没有4个字符,但我明白了。只需将匹配的正则表达式字符更改为[a-fA-F0-9]。它仍然会匹配不希望匹配的内容,但看起来仍然符合原始问题的意图。
亚当·西尔斯

2
看起来很干净。不过,令我惊讶的是,没有System .Net类可以做到这一点。
saarp 2012年

不太确定为什么会有System类来执行此操作。并非所有语言都使用转义字符序列(例如,不是VB.NET)。因此,这将是特定于语言的。您可能可以使用Microsoft.CSharp.CSharpCodeProvider来执行此操作,但是这似乎有些过分。
亚当·希尔斯

3
@AdamSills如果第三方服务器正在返回它们,则将需要对其进行解码。在Net或Web类中,当您要转换这些字符时,静态方法会很不错。
James Jeffery 2013年

22

对于Unescape,您可以简单地使用以下功能:

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

System.Uri.UnescapeDataString(string)

我建议使用此方法(与UTF-8搭配使用效果更好):

UnescapeDataString(string)

1
在我使用“ System.Text.RegularExpressions.Regex.Unescape”的情况下,我得到了更好的结果。
霍斯罗

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

4

作为单线:

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

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

所有非ASCII字符都将转换为它们的Unicode代码点表示形式,并附加到最​​终字符串中。


1

一个小补丁@Adam希尔斯的回答解决了FormatException在其中输入字符串类案件“:\ u00ab \ otherdirectory \ C ”加上RegexOptions.Compiled使Regex编译更快:

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

1

这是我当前的实现:

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

通过测试:

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

编码值: "\ud840\udc00"

此实现利用StringBuilderCache(参考源链接)


0

您需要Convert()Encoding类中使用该方法:

  • 创建一个Encoding表示ASCII编码的对象
  • 创建一个Encoding表示Unicode编码的对象
  • Encoding.Convert()使用源编码,目标编码和要编码的字符串进行调用

有一个例子在这里

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

4
我已经尝试过了。它的问题在于它将Unicode字符π(\ u03a0)转换为“?”。我需要将其转换为“ \ u03a0”。
阿里

0

要存储实际的Unicode代码点,您必须首先将String的UTF-16代码单元解码为UTF-32代码单元(当前与Unicode代码点相同)。使用System.Text.Encoding.UTF32.GetBytes()该,然后将所得的字节写入StringBuilder根据需要,即

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(); 
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.