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
DecodeEncodedNonAsciiCharacters rzuci wyjątek FormatException dla ciągów takich jak "\\ użytkownik" – vovafeldman
\ 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. –
Wygląda ładnie i czysto. Mimo to jestem zaskoczony, że nie ma klasy System .Net, która to zrobi. – saarp