Преобразование строки Юникода в экранированную строку ASCII
Как я могу преобразовать эту строку:
This string contains the Unicode character Pi(π)
в экранированную строку ASCII:
This string contains the Unicode character Pi(u03a0)
и наоборот?
текущая кодировка, доступная в C#, преобразует символ π в "?". Мне нужно сохранить этот характер.
9 ответов:
Это идет туда и обратно в и из формата \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(); } ); } }
выходы:
эта функция содержит символ Юникода pi (π)
эта функция содержит символ Юникода pi (\u03a0)
эта функция содержит символ Юникода pi (π)
на Unescape вы можете просто использовать этот функции:
System.Text.RegularExpressions.Regex.Unescape(string) System.Uri.UnescapeDataString(string)
Я предлагаю использовать этот метод (он лучше работает с UTF-8):
UnescapeDataString(string)
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); }
как однострочный:
var result = Regex.Replace(input, @"[^\x00-\x7F]", c => string.Format(@"\u{0:x4}", (int)c.Value[0]));
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, преобразуются в их представление кодовой точки Юникода и добавляются к последней строке.
небольшой патч к ответу @Adam Sills, который решает
FormatException
в случаях, когда входная строка типа "c:\u00ab\otherdirectory\" плюс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, @"\"); }
вот моя текущая реализация:
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 (ссылка на источник ссылку)
вы должны использовать
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); } } }
чтобы сохранить фактические кодовые точки Юникода, вы должны сначала декодировать кодовые единицы строки UTF-16 в кодовые единицы UTF-32 (которые в настоящее время совпадают с кодовыми точками Юникода). Используйте
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(); }