public string DecodeFromUtf8(string utf8String)
{
// copy the string as UTF-8 bytes.
byte[] utf8Bytes = new byte[utf8String.Length];
for (int i = 0; i < utf8String.Length; ++i)
{
//Debug.Assert( 0 <= utf8String[i] && utf8String[i] <= 255,
//"the char must be in byte's range");
utf8Bytes[i] = (byte)utf8String[i];
}
return Encoding.UTF8.GetString(utf8Bytes, 0, utf8Bytes.Length);
}
this code doesn't work for me do you have any good ideas?
i need the unicode array for russian fonts like this
public static readonly ReadOnlyCollection<char> Unicodes = Array.AsReadOnly(new char[]
{
'\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007',
'\u0008', '\u0009', '\u000A', '\u000B', '\u000C', '\u000D', '\u000E', '\u000F',
'\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016', '\u0017',
'\u0018', '\u0019', '\u001A', '\u001B', '\u001C', '\u001D', '\u001E', '\u001F',
'\u0020', '\u0021', '\u0022', '\u0023', '\u0024', '\u0025', '\u0026', '\u0027',
'\u0028', '\u0029', '\u002A', '\u002B', '\u002C', '\u002D', '\u002E', '\u002F',
'\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037',
'\u0038', '\u0039', '\u003A', '\u003B', '\u003C', '\u003D', '\u003E', '\u003F',
'\u0040', '\u0041', '\u0042', '\u0043', '\u0044', '\u0045', '\u0046', '\u0047',
'\u0048', '\u0049', '\u004A', '\u004B', '\u004C', '\u004D', '\u004E', '\u004F',
'\u0050', '\u0051', '\u0052', '\u0053', '\u0054', '\u0055', '\u0056', '\u0057',
'\u0058', '\u0059', '\u005A', '\u005B', '\u005C', '\u005D', '\u005E', '\u005F',
'\u0060', '\u0061', '\u0062', '\u0063', '\u0064', '\u0065', '\u0066', '\u0067',
'\u0068', '\u0069', '\u006A', '\u006B', '\u006C', '\u006D', '\u006E', '\u006F',
'\u0070', '\u0071', '\u0072', '\u0073', '\u0074', '\u0075', '\u0076', '\u0077',
'\u0078', '\u0079', '\u007A', '\u007B', '\u007C', '\u007D', '\u007E', '\u007F',
'\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD',
'\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD',
'\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD',
'\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD', '\uFFFD',
'\u00A0', '\u058E', '\u0587', '\u0589', '\u0029', '\u0028', '\u00BB', '\u00AB',
'\u2015', '\u00B7', '\u055D', '\u002C', '\u2010', '\u058A', '\u2026', '\u055C',
'\u055B', '\u055E', '\u0531', '\u0561', '\u0532', '\u0562', '\u0533', '\u0563',
'\u0534', '\u0564', '\u0535', '\u0565', '\u0536', '\u0566', '\u0537', '\u0567',
'\u0538', '\u0568', '\u0539', '\u0569', '\u053A', '\u056A', '\u053B', '\u056B',
'\u053C', '\u056C', '\u053D', '\u056D', '\u053E', '\u056E', '\u053F', '\u056F',
'\u0540', '\u0570', '\u0541', '\u0571', '\u0542', '\u0572', '\u0543', '\u0573',
'\u0544', '\u0574', '\u0545', '\u0575', '\u0546', '\u0576', '\u0547', '\u0577',
'\u0548', '\u0578', '\u0549', '\u0579', '\u054A', '\u057A', '\u054B', '\u057B',
'\u054C', '\u057C', '\u054D', '\u057D', '\u054E', '\u057E', '\u054F', '\u057F',
'\u0550', '\u0580', '\u0551', '\u0581', '\u0552', '\u0582', '\u0553', '\u0583',
'\u0554', '\u0584', '\u0555', '\u0585', '\u0556', '\u0586', '\u055A', '\uFFFD' });
Your string seems to be ArmSCII-8 .
Adapted from an old encoder/decoder I had written for VISCII:
namespace Utilities
{
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
/// <summary>
/// ArmSCII8 (https://en.wikipedia.org/wiki/ArmSCII#ArmSCII-8)
/// encoding for C#.
/// Fast table-based implementation not based on MappedEncoding.
/// Fully thread safe/reentrant (because ArmSCII8Encoder is fully thread
/// safe/reentrant and ArmSCII8Decoder is always used with flush = true).
/// </summary>
public class ArmSCII8EncodingSimple : Encoding
{
// Taken from https://en.wikipedia.org/wiki/ArmSCII#ArmSCII-8 .
// Includes parts of the ISO-8859-1 in the ranges 00–1F and 7F–9F.
// Doesn't define anything for FF.
public static readonly ReadOnlyCollection<char> Unicodes = Array.AsReadOnly(new char[]
{
'\u0000', '\u0001', '\u0002', '\u0003', '\u0004', '\u0005', '\u0006', '\u0007',
'\u0008', '\u0009', '\u000A', '\u000B', '\u000C', '\u000D', '\u000E', '\u000F',
'\u0010', '\u0011', '\u0012', '\u0013', '\u0014', '\u0015', '\u0016', '\u0017',
'\u0018', '\u0019', '\u001A', '\u001B', '\u001C', '\u001D', '\u001E', '\u001F',
'\u0020', '\u0021', '\u0022', '\u0023', '\u0024', '\u0025', '\u0026', '\u0027',
'\u0028', '\u0029', '\u002A', '\u002B', '\u002C', '\u002D', '\u002E', '\u002F',
'\u0030', '\u0031', '\u0032', '\u0033', '\u0034', '\u0035', '\u0036', '\u0037',
'\u0038', '\u0039', '\u003A', '\u003B', '\u003C', '\u003D', '\u003E', '\u003F',
'\u0040', '\u0041', '\u0042', '\u0043', '\u0044', '\u0045', '\u0046', '\u0047',
'\u0048', '\u0049', '\u004A', '\u004B', '\u004C', '\u004D', '\u004E', '\u004F',
'\u0050', '\u0051', '\u0052', '\u0053', '\u0054', '\u0055', '\u0056', '\u0057',
'\u0058', '\u0059', '\u005A', '\u005B', '\u005C', '\u005D', '\u005E', '\u005F',
'\u0060', '\u0061', '\u0062', '\u0063', '\u0064', '\u0065', '\u0066', '\u0067',
'\u0068', '\u0069', '\u006A', '\u006B', '\u006C', '\u006D', '\u006E', '\u006F',
'\u0070', '\u0071', '\u0072', '\u0073', '\u0074', '\u0075', '\u0076', '\u0077',
'\u0078', '\u0079', '\u007A', '\u007B', '\u007C', '\u007D', '\u007E', '\u007F',
'\u0080', '\u0081', '\u0082', '\u0083', '\u0084', '\u0085', '\u0086', '\u0087',
'\u0088', '\u0089', '\u008A', '\u008B', '\u008C', '\u008D', '\u008E', '\u008F',
'\u0090', '\u0091', '\u0092', '\u0093', '\u0094', '\u0095', '\u0096', '\u0097',
'\u0098', '\u0099', '\u009A', '\u009B', '\u009C', '\u009D', '\u009E', '\u009F',
'\u00A0', '\u058E', '\u0587', '\u0589', '\u0029', '\u0028', '\u00BB', '\u00AB',
'\u2015', '\u00B7', '\u055D', '\u002C', '\u2010', '\u058A', '\u2026', '\u055C',
'\u055B', '\u055E', '\u0531', '\u0561', '\u0532', '\u0562', '\u0533', '\u0563',
'\u0534', '\u0564', '\u0535', '\u0565', '\u0536', '\u0566', '\u0537', '\u0567',
'\u0538', '\u0568', '\u0539', '\u0569', '\u053A', '\u056A', '\u053B', '\u056B',
'\u053C', '\u056C', '\u053D', '\u056D', '\u053E', '\u056E', '\u053F', '\u056F',
'\u0540', '\u0570', '\u0541', '\u0571', '\u0542', '\u0572', '\u0543', '\u0573',
'\u0544', '\u0574', '\u0545', '\u0575', '\u0546', '\u0576', '\u0547', '\u0577',
'\u0548', '\u0578', '\u0549', '\u0579', '\u054A', '\u057A', '\u054B', '\u057B',
'\u054C', '\u057C', '\u054D', '\u057D', '\u054E', '\u057E', '\u054F', '\u057F',
'\u0550', '\u0580', '\u0551', '\u0581', '\u0552', '\u0582', '\u0553', '\u0583',
'\u0554', '\u0584', '\u0555', '\u0585', '\u0556', '\u0586', '\u055A', '\0'/**/,
});
private ArmSCII8Decoder decoder;
private ArmSCII8Encoder encoder;
/// <summary>
/// This should be thread safe. The worst case is that two instances
/// of ArmSCII8Decoder are created at the same time, but this isn't
/// a problem, because ArmSCII8Decoder as used in this class is
/// stateless.
/// </summary>
protected ArmSCII8Decoder Decoder
{
get
{
ArmSCII8Decoder decoder2 = decoder;
// Lazy creation of Encoder
if (object.ReferenceEquals(decoder2, null))
{
decoder2 = decoder = new ArmSCII8Decoder();
}
DecoderFallback decoderFallback = DecoderFallback;
// If the Fallback has changed from the last call, update it
if (!object.ReferenceEquals(decoderFallback, null) && !object.ReferenceEquals(decoderFallback, decoder2.Fallback))
{
decoder2.Fallback = decoderFallback;
}
return decoder2;
}
}
/// <summary>
/// This should be thread safe. The worst case is that two instances
/// of ArmSCII8Encoder are created at the same time, but this isn't
/// a problem, because ArmSCII8Encoder as used in this class is
/// stateless.
/// </summary>
protected ArmSCII8Encoder Encoder
{
get
{
ArmSCII8Encoder encoder2 = encoder;
// Lazy creation of Encoder
if (object.ReferenceEquals(encoder2, null))
{
encoder = encoder2 = new ArmSCII8Encoder();
}
EncoderFallback encoderFallback = EncoderFallback;
// If the Fallback has changed from the last call, update it
if (!object.ReferenceEquals(encoderFallback, null) && !object.ReferenceEquals(encoderFallback, encoder2.Fallback))
{
encoder2.Fallback = encoderFallback;
}
return encoder2;
}
}
public override string BodyName
{
get
{
return "x-armscii-8-simple";
}
}
public override string EncodingName
{
get
{
return BodyName;
}
}
public override bool IsSingleByte
{
get
{
return true;
}
}
public override object Clone()
{
var encoding = (ArmSCII8EncodingSimple)base.Clone();
// We reset the encoder and decoder of the cloned instance,
// because otherwise they would be shared between the two
// instances.
encoding.decoder = null;
encoding.encoder = null;
return encoding;
}
public override Decoder GetDecoder()
{
return new ArmSCII8Decoder();
}
public override Encoder GetEncoder()
{
return new ArmSCII8Encoder();
}
public override int GetByteCount(char[] chars, int index, int count)
{
return Encoder.GetByteCount(chars, index, count, true);
}
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
{
return Encoder.GetBytes(chars, charIndex, charCount, bytes, byteIndex, true);
}
public override int GetCharCount(byte[] bytes, int index, int count)
{
return Decoder.GetCharCount(bytes, index, count, true);
}
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
{
return Decoder.GetChars(bytes, byteIndex, byteCount, chars, charIndex, true);
}
public override int GetMaxByteCount(int charCount)
{
return charCount;
}
public override int GetMaxCharCount(int byteCount)
{
return byteCount;
}
}
/// <summary>
/// Fully thread safe/reentrant.
/// </summary>
public class ArmSCII8Decoder : Decoder
{
private static readonly char[] Unicodes = ArmSCII8EncodingSimple.Unicodes.ToArray();
public override int GetCharCount(byte[] bytes, int index, int count)
{
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (index < 0 || index > bytes.Length)
{
throw new ArgumentOutOfRangeException("index");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
if (index + count > bytes.Length)
{
throw new ArgumentOutOfRangeException("bytes");
}
// The fallbackBuffer is created on-demand. The instance
// FallbackBuffer isn't used because it wouldn't be thread safe.
DecoderFallbackBuffer fallbackBuffer = null;
int ret = 0;
int count2 = index + count;
for (; index < count2; index++)
{
byte b = bytes[index];
char ch = Unicodes[b];
if (ch != '\0' || b == 0)
{
ret++;
}
else
{
if (fallbackBuffer == null)
{
fallbackBuffer = (Fallback ?? DecoderFallback.ReplacementFallback).CreateFallbackBuffer();
}
// Fallback
if (fallbackBuffer.Fallback(new[] { b }, index))
{
HandleFallbackCount(fallbackBuffer, ref ret);
}
}
}
return ret;
}
public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
{
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (byteIndex < 0 || byteIndex > bytes.Length)
{
throw new ArgumentOutOfRangeException("byteIndex");
}
if (byteCount < 0)
{
throw new ArgumentOutOfRangeException("byteCount");
}
if (byteIndex + byteCount > bytes.Length)
{
throw new ArgumentOutOfRangeException("bytes");
}
if (chars == null)
{
throw new ArgumentNullException("chars");
}
if (charIndex < 0 || charIndex > chars.Length)
{
throw new ArgumentOutOfRangeException("charIndex");
}
// The fallbackBuffer is created on-demand. The instance
// FallbackBuffer isn't used because it wouldn't be thread safe.
DecoderFallbackBuffer fallbackBuffer = null;
int byteCount2 = byteCount + byteIndex;
int charIndex2 = charIndex;
for (; byteIndex < byteCount2; byteIndex++)
{
byte b = bytes[byteIndex];
// chars between 0 and 127 are equal in Unicode and ArmSCII8
if (b >= 0 && b <= 127)
{
WriteChar(chars, charIndex2, (char)b);
charIndex2++;
}
else
{
char ch = Unicodes[b];
if (ch != '\0' || b == 0)
{
WriteChar(chars, charIndex2, ch);
charIndex2++;
}
else
{
if (fallbackBuffer == null)
{
fallbackBuffer = (Fallback ?? DecoderFallback.ReplacementFallback).CreateFallbackBuffer();
}
// Fallback
if (fallbackBuffer.Fallback(new[] { b }, byteIndex))
{
HandleFallbackWrite(fallbackBuffer, chars, ref charIndex2);
}
}
}
}
return charIndex2 - charIndex;
}
protected static void HandleFallbackCount(DecoderFallbackBuffer fallbackBuffer, ref int count)
{
while (fallbackBuffer.Remaining > 0)
{
fallbackBuffer.GetNextChar();
count++;
}
}
protected static void HandleFallbackWrite(DecoderFallbackBuffer fallbackBuffer, char[] chars, ref int charIndex)
{
while (fallbackBuffer.Remaining > 0)
{
char ch = fallbackBuffer.GetNextChar();
WriteChar(chars, charIndex, ch);
charIndex++;
}
}
// Remove the next line if using .NET < 4.5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static void WriteChar(char[] chars, int charIndex, char ch)
{
if (charIndex >= chars.Length)
{
throw new ArgumentException("bytes");
}
chars[charIndex] = ch;
}
}
/// <summary>
/// An instance is thread safe/fully reentrant if the methods are always
/// called with flush = true.
/// </summary>
public class ArmSCII8Encoder : Encoder
{
private static readonly byte[] ArmSCII8s;
// Buffer for High/Low surrogates. Note that this property is read
// but not written if the methods are always used with flush = true.
protected char HighSurrogate { get; set; }
static ArmSCII8Encoder()
{
ArmSCII8s = new byte[1 + ArmSCII8EncodingSimple.Unicodes.Max()];
for (int i = 0; i < ArmSCII8EncodingSimple.Unicodes.Count; i++)
{
char ch = ArmSCII8EncodingSimple.Unicodes[i];
if (i == 0 || (ArmSCII8s[ch] == 0 && ch != '\0'))
{
ArmSCII8s[ch] = (byte)i;
}
}
}
public override int GetByteCount(char[] chars, int index, int count, bool flush)
{
if (chars == null)
{
throw new ArgumentNullException("chars");
}
if (index < 0 || index > chars.Length)
{
throw new ArgumentOutOfRangeException("index");
}
if (count < 0)
{
throw new ArgumentOutOfRangeException("count");
}
if (index + count > chars.Length)
{
throw new ArgumentOutOfRangeException("chars");
}
// The fallbackBuffer is created on-demand. The instance
// FallbackBuffer isn't used because it wouldn't be thread safe.
EncoderFallbackBuffer fallbackBuffer = null;
char highSurrogate = HighSurrogate;
int ret = 0;
int count2 = index + count;
for (; index < count2; index++)
{
char ch = chars[index];
if (highSurrogate != 0)
{
if (fallbackBuffer == null)
{
fallbackBuffer = (Fallback ?? EncoderFallback.ReplacementFallback).CreateFallbackBuffer();
}
// If we have a High/Low surrogates couple, we pass them
// together
if (char.IsLowSurrogate(ch))
{
if (fallbackBuffer.Fallback(highSurrogate, ch, index - 1))
{
HandleFallbackCount(fallbackBuffer, ref ret);
}
highSurrogate = '\0';
continue;
}
else
{
// First we pass the High surrogate to the Fallback
if (fallbackBuffer.Fallback(highSurrogate, index - 1))
{
HandleFallbackCount(fallbackBuffer, ref ret);
}
highSurrogate = '\0';
// Then we fall-through normal handling
}
}
if (ch < ArmSCII8s.Length && (ArmSCII8s[ch] != 0 || ch == '\0'))
{
ret++;
}
else
{
// High/low surrogate handling, done through buffer
if (char.IsHighSurrogate(ch))
{
highSurrogate = ch;
}
else
{
if (fallbackBuffer == null)
{
fallbackBuffer = (Fallback ?? EncoderFallback.ReplacementFallback).CreateFallbackBuffer();
}
// Fallback
if (fallbackBuffer.Fallback(ch, index))
{
HandleFallbackCount(fallbackBuffer, ref ret);
}
}
}
}
if (flush)
{
if (highSurrogate != 0)
{
if (fallbackBuffer == null)
{
fallbackBuffer = (Fallback ?? EncoderFallback.ReplacementFallback).CreateFallbackBuffer();
}
if (fallbackBuffer.Fallback(highSurrogate, index - 1))
{
HandleFallbackCount(fallbackBuffer, ref ret);
}
}
}
return ret;
}
public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex, bool flush)
{
if (chars == null)
{
throw new ArgumentNullException("chars");
}
if (charIndex < 0 || charIndex > chars.Length)
{
throw new ArgumentOutOfRangeException("charIndex");
}
if (charCount < 0)
{
throw new ArgumentOutOfRangeException("charCount");
}
if (charIndex + charCount > chars.Length)
{
throw new ArgumentOutOfRangeException("chars");
}
if (bytes == null)
{
throw new ArgumentNullException("bytes");
}
if (byteIndex < 0 || byteIndex > bytes.Length)
{
throw new ArgumentOutOfRangeException("byteIndex");
}
// The fallbackBuffer is created on-demand. The instance
// FallbackBuffer isn't used because it wouldn't be thread safe.
EncoderFallbackBuffer fallbackBuffer = null;
// Written only on flush = false
char highSurrogate = HighSurrogate;
int charCount2 = charIndex + charCount;
int byteIndex2 = byteIndex;
for (; charIndex < charCount2; charIndex++)
{
char ch = chars[charIndex];
if (highSurrogate != 0)
{
if (fallbackBuffer == null)
{
fallbackBuffer = (Fallback ?? EncoderFallback.ReplacementFallback).CreateFallbackBuffer();
}
// If we have a High/Low surrogates couple, we pass them
// together
if (char.IsLowSurrogate(ch))
{
if (fallbackBuffer.Fallback(highSurrogate, ch, charIndex - 1))
{
HandleFallbackWrite(fallbackBuffer, bytes, ref byteIndex2);
}
highSurrogate = '\0';
continue;
}
else
{
// First we pass the High surrogate to the Fallback
if (fallbackBuffer.Fallback(highSurrogate, charIndex - 1))
{
HandleFallbackWrite(fallbackBuffer, bytes, ref byteIndex2);
}
highSurrogate = '\0';
// Then we fall-through normal handling
}
}
byte b;
if (ch < ArmSCII8s.Length && ((b = ArmSCII8s[ch]) != 0 || ch == '\0'))
{
// Recognized character
WriteByte(bytes, byteIndex2, b);
byteIndex2++;
}
else
{
// High/low surrogate handling, done through buffer
if (char.IsHighSurrogate(ch))
{
highSurrogate = ch;
}
else
{
if (fallbackBuffer == null)
{
fallbackBuffer = (Fallback ?? EncoderFallback.ReplacementFallback).CreateFallbackBuffer();
}
// Fallback
if (fallbackBuffer.Fallback(ch, charIndex))
{
HandleFallbackWrite(fallbackBuffer, bytes, ref byteIndex2);
}
}
}
}
if (flush)
{
if (highSurrogate != 0)
{
if (fallbackBuffer == null)
{
fallbackBuffer = (Fallback ?? EncoderFallback.ReplacementFallback).CreateFallbackBuffer();
}
if (fallbackBuffer.Fallback(highSurrogate, charIndex - 1))
{
HandleFallbackWrite(fallbackBuffer, bytes, ref byteIndex2);
}
}
}
else
{
HighSurrogate = highSurrogate;
}
return byteIndex2 - byteIndex;
}
protected static void HandleFallbackCount(EncoderFallbackBuffer fallbackBuffer, ref int count)
{
while (fallbackBuffer.Remaining > 0)
{
char ch = fallbackBuffer.GetNextChar();
if (!(ch < ArmSCII8s.Length && (ArmSCII8s[ch] != 0 || ch == '\0')))
{
throw new EncoderFallbackException();
}
count++;
}
}
protected static void HandleFallbackWrite(EncoderFallbackBuffer fallbackBuffer, byte[] bytes, ref int byteIndex)
{
while (fallbackBuffer.Remaining > 0)
{
char ch = fallbackBuffer.GetNextChar();
byte b;
if (!(ch < ArmSCII8s.Length && ((b = ArmSCII8s[ch]) != 0 || ch == '\0')))
{
throw new EncoderFallbackException();
}
WriteByte(bytes, byteIndex, b);
byteIndex++;
}
}
// Remove the next line if using .NET < 4.5
[MethodImpl(MethodImplOptions.AggressiveInlining)]
protected static void WriteByte(byte[] bytes, int byteIndex, byte b)
{
if (byteIndex == bytes.Length)
{
throw new ArgumentException("bytes");
}
bytes[byteIndex] = b;
}
}
}
Then use it like:
public static string DecodeFromArmSCII8(string str) {
// copy the string as UTF-8 bytes.
byte[] bytes = Encoding.GetEncoding("iso-8859-1").GetBytes(str);
return new ArmSCII8EncodingSimple().GetString(bytes);
}
and
string str = DecodeFromArmSCII8("سñïÇñáëÛ³Ý ²ÉÇݳ Ø.");
The Encoding.GetEncoding("iso-8859-1").GetBytes(str)
returns the original byte[]
array. Note that if you have the original byte[]
you can directly use the ArmSCII8EncodingFast
.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.