source

부호화를 수동으로 지정하지 않고 C# 내의 문자열을 일관된 바이트 형식으로 표시하려면 어떻게 해야 합니까?

gigabyte 2023. 4. 19. 23:09
반응형

부호화를 수동으로 지정하지 않고 C# 내의 문자열을 일관된 바이트 형식으로 표시하려면 어떻게 해야 합니까?

「」를 해야 ?string a까지byte[]「 」 「 」 。 " 。NET(C#)는?

스트링을 암호화합니다.변환하지 않고 암호화할 수 있지만, 여기서 인코딩이 재생되는 이유를 알고 싶습니다.

또, 부호화가 고려되어야 하는 이유는 무엇입니까?문자열이 저장되어 있는 바이트를 간단하게 얻을 수 없습니까?문자 인코딩에 의존하는 이유는 무엇입니까?

이 답변과는 달리 바이트를 해석할 필요가 없다면 인코딩에 대해 걱정할 필요가 없습니다.

말씀하신 것처럼 단순히 "문자열이 저장된 바이트를 얻는"이 목표입니다.
(물론 바이트에서 문자열을 재구성할 수 있습니다.)

그 목표를 위해 왜 사람들이 계속 당신에게 암호화가 필요하다고 말하는지 솔직히 이해할 수 없습니다.당신은 이것에 대한 인코딩에 대해 걱정할 필요가 없습니다.

대신 다음 작업을 수행합니다.

static byte[] GetBytes(string str)
{
    byte[] bytes = new byte[str.Length * sizeof(char)];
    System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
    return bytes;
}

// Do NOT use on arbitrary bytes; only use on GetBytes's output on the SAME system
static string GetString(byte[] bytes)
{
    char[] chars = new char[bytes.Length / sizeof(char)];
    System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
    return new string(chars);
}

사용하고 있는 프로그램(또는 다른 프로그램)이 바이트를 해석하려고 하지 않는 한(분명히 의도하고 있다고는 말하지 않았지만) 이 방법에는 문제가 없습니다.암호화에 대해 걱정하는 것은 진짜 이유 없이 당신의 삶을 더 복잡하게 만들 뿐이다.

이 접근방식의 기타 이점:문자열에 잘못된 문자가 포함되더라도 상관없습니다. 데이터를 가져오고 원래 문자열을 재구성할 수 있기 때문입니다.

바이트만 보고 있기 때문에 똑같이 부호화 및 디코딩됩니다.

다만, 특정의 인코딩을 사용하고 있는 경우는, 무효인 문자를 인코딩/복호화하는 문제가 발생합니다.

이것은, 문자열(ASCII, UTF-8, ...)의 부호화에 의해서 다릅니다.

예를 들어 다음과 같습니다.

byte[] b1 = System.Text.Encoding.UTF8.GetBytes (myString);
byte[] b2 = System.Text.Encoding.ASCII.GetBytes (myString);

부호화가 중요한 이유는 다음과 같습니다.

string pi = "\u03a0";
byte[] ascii = System.Text.Encoding.ASCII.GetBytes (pi);
byte[] utf8 = System.Text.Encoding.UTF8.GetBytes (pi);

Console.WriteLine (ascii.Length); //Will print 1
Console.WriteLine (utf8.Length); //Will print 2
Console.WriteLine (System.Text.Encoding.ASCII.GetString (ascii)); //Will print '?'

ASCII는 단순히 특수문자를 다룰 수 있는 장비가 아니다.

내부적으로는,NET 프레임워크는 UTF-16을 사용하여 스트링을 나타냅니다.따라서 단순히 그 바이트를 정확하게 취득할 필요가 있습니다.NET 사용, 사용System.Text.Encoding.Unicode.GetBytes (...).

의 「문자 부호화」를 참조해 주세요.자세한 것은, NET Framework(MSDN)를 참조해 주세요.

받아들여진 답은 매우 복잡하다.포함을 사용합니다.이에 대한 NET 클래스:

const string data = "A string with international characters: Norwegian: ÆØÅæøå, Chinese: 喂 谢谢";
var bytes = System.Text.Encoding.UTF8.GetBytes(data);
var decoded = System.Text.Encoding.UTF8.GetString(bytes);

필요 없다면 바퀴를 재발명하지 마...

BinaryFormatter bf = new BinaryFormatter();
byte[] bytes;
MemoryStream ms = new MemoryStream();

string orig = "喂 Hello 谢谢 Thank You";
bf.Serialize(ms, orig);
ms.Seek(0, 0);
bytes = ms.ToArray();

MessageBox.Show("Original bytes Length: " + bytes.Length.ToString());

MessageBox.Show("Original string Length: " + orig.Length.ToString());

for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo encrypt
for (int i = 0; i < bytes.Length; ++i) bytes[i] ^= 168; // pseudo decrypt

BinaryFormatter bfx = new BinaryFormatter();
MemoryStream msx = new MemoryStream();            
msx.Write(bytes, 0, bytes.Length);
msx.Seek(0, 0);
string sx = (string)bfx.Deserialize(msx);

MessageBox.Show("Still intact :" + sx);

MessageBox.Show("Deserialize string Length(still intact): " 
    + sx.Length.ToString());

BinaryFormatter bfy = new BinaryFormatter();
MemoryStream msy = new MemoryStream();
bfy.Serialize(msy, sx);
msy.Seek(0, 0);
byte[] bytesy = msy.ToArray();

MessageBox.Show("Deserialize bytes Length(still intact): " 
   + bytesy.Length.ToString());

이것은 인기 있는 질문입니다.질문 작성자가 무엇을 묻고 있는지, 그리고 그것이 가장 일반적인 요구와는 다르다는 것을 이해하는 것이 중요합니다.불필요한 코드의 오용을 막기 위해 후자부터 대답했습니다.

일반적인 요구

모든 문자열에는 문자 집합과 인코딩이 있습니다.「」를 System.String로 늘어선 것에 System.Byte문자 집합과 인코딩이 남아 있습니다.대부분의 경우 필요한 문자 집합과 인코딩 및 를 알 수 있습니다.NET을 사용하면, 간단하게 「변환과 함께 카피」할 수 있습니다.적절한 것을 선택하기만 하면 됩니다.Encoding를 누릅니다

// using System.Text;
Encoding.UTF8.GetBytes(".NET String to byte array")

변환에서는 대상 문자 세트 또는 인코딩이 원본에 있는 문자를 지원하지 않는 경우를 처리해야 할 수 있습니다.예외, 대체 또는 건너뛰기 중에서 선택할 수 있습니다.디폴트 정책에서는 '?'를 치환합니다.

// using System.Text;
var text = Encoding.ASCII.GetString(Encoding.ASCII.GetBytes("You win €100")); 
                                                      // -> "You win ?100"

전환이 반드시 무손실인 것은 아닙니다.

★★의 경우:★★System.String유니코드

유일한 혼란스러운 것은 그것이다.NET 는, 문자 세트의 이름을, 그 문자 세트의 특정의 부호화의 이름으로 사용합니다. Encoding.Unicode라고 Encoding.UTF16.

대부분의 용도는 이것으로 끝입니다. 그게 네가 필요한 거라면, 여기서 그만 읽어.인코딩이 무엇인지 모를 경우 재미있는 Joel Spolsky 기사를 참조하십시오.

특정 니즈

여기서 저자의 질문은 다음과 같습니다. "모든 문자열은 바이트 배열로 저장됩니다.왜 단순히 그 바이트를 가질 수 없는 거죠?

그는 어떤 전환도 원하지 않는다.

C# 사양부터:

C# 의 문자 및 문자열 처리에서는, Unicode 인코딩을 사용합니다.char 타입은 UTF-16 코드 유닛을 나타내고 문자열 타입은 UTF-16 코드 유닛의 시퀀스를 나타냅니다.

따라서 늘 변환(UTF-16에서 UTF-16으로)을 요구하면 원하는 결과를 얻을 수 있습니다.

Encoding.Unicode.GetBytes(".NET String to byte array")

하지만 암호화에 대한 언급을 피하려면 다른 방법으로 해야 합니다.중간 데이터 유형이 허용 가능한 경우 이를 위한 개념적 단축키가 있습니다.

".NET String to byte array".ToCharArray()

원하는 데이터 유형을 얻을 수 없지만, Mehrdad의 답변에는 BlockCopy를 사용하여 이 Char 배열을 바이트 배열로 변환하는 방법이 나와 있습니다.그러나 이것은 문자열을 두 번 복사합니다!또, 부호화 고유의 코드(데이터 타입)를 너무 명시적으로 사용하고 있습니다.System.Char.

String이 저장되어 있는 실제 바이트에 도달하려면 포인터를 사용해야 합니다.fixed하면 valuesstatement의 수 있습니다.C# 사 c :

[For] 타입 문자열 표현식... 이니셜라이저는 문자열의 첫 번째 문자의 주소를 계산합니다.

코드를 .RuntimeHelpers.OffsetToStringDataraw "는 필요한 바이트 수를 복사합니다.

// using System.Runtime.InteropServices
unsafe byte[] GetRawBytes(String s)
{
    if (s == null) return null;
    var codeunitCount = s.Length;
    /* We know that String is a sequence of UTF-16 code units 
       and such code units are 2 bytes */
    var byteCount = codeunitCount * 2; 
    var bytes = new byte[byteCount];
    fixed(void* pRaw = s)
    {
        Marshal.Copy((IntPtr)pRaw, bytes, 0, byteCount);
    }
    return bytes;
}

@CodesInChaos가 지적했듯이 결과는 기계의 엔디안성에 따라 달라집니다.그러나 질문 작성자는 그것과 관련이 없다.

1글자는 1바이트 이상(최대 6바이트)으로 나타낼 수 있으며 인코딩에 따라 이러한 바이트는 다르게 취급되기 때문에 부호화를 고려해야 합니다.

Joel은 다음과 같은 글을 올렸습니다.

모든 소프트웨어 개발자는 Unicode와 문자 집합에 대해 절대적으로 알아야 합니다(변명 없음).

첫 방법)은 다른했습니다. '알겠습니다.'를.System.Text.Encoding임스스네

후속 질문: 인코딩을 선택해야 하는 이유는 무엇입니까?왜 스트링 클래스 자체에서 그걸 얻을 수 없는 거죠?

정답은 두 부분으로 나누어져 있습니다.

우선 문자열 클래스에서 내부적으로 사용되는 바이트는 중요하지 않으며, 바이트가 사용되었다고 가정할 때마다 버그가 발생할 수 있습니다.

사용하고 있는 프로그램이 에 완전히 포함되어 있는 경우.네트워크상에서 데이터를 송신하고 있는 경우에서도, 네트워크상에서 문자열의 바이트 어레이를 취득하는 것에 대해 걱정할 필요는 없습니다.대신 을 사용합니다.Net Serialization: 데이터 전송에 대해 우려합니다.실제 바이트에 대한 걱정이 없어졌습니다.시리얼라이제이션 포메터가 대신합니다.

한편, 이러한 바이트를 보증할 수 없는 장소에 송신하고 있는 경우는, 로부터 데이터가 풀 됩니다.순시리얼라이즈드 스트림?이 경우 인코딩에 대해 걱정할 필요가 있습니다. 왜냐하면 이 외부 시스템은 분명히 관심을 가지기 때문입니다.따라서 문자열에서 사용되는 내부 바이트는 중요하지 않습니다.따라서, 수신측에서 이 인코딩에 대해 명시적으로 지정할 수 있도록 인코딩을 선택해야 합니다.이 인코딩은 에서 내부적으로 사용되는 인코딩과 동일합니다.그물.

이 경우 가능하면 문자열 변수에 의해 메모리에 저장된 실제 바이트를 사용하면 바이트 스트림을 만드는 작업이 줄어들 수 있다는 점을 이해합니다.다만, 출력의 내용을 상대측에서 확실히 이해시키는 것, 및 부호화를 명시적으로 실시할 필요가 있는 것을 확인하는 것에 비하면, 그다지 중요하지 않습니다.또한 내부 바이트를 일치시키려면 이미 다음 명령을 선택하면 됩니다.Unicode이치노

고르다Unicodeencoding은 tell 입니다.[Net] : 기본 바이트를 사용합니다.새로운 Unicode-Plus가 나올 때 이 인코딩을 선택해야 합니다.프로그램을 중단하지 않고 더 새롭고 더 나은 인코딩 모델을 사용하려면 Net Runtime이 자유로워야 합니다.그러나 현재(그리고 예측 가능한 미래) 유니코드 인코딩을 선택하는 것만으로 원하는 것을 얻을 수 있습니다.

스트링을 와이어로 고쳐 써야 한다는 것도 중요합니다.또한 일치하는 인코딩을 사용하는 경우에도 비트 패턴의 적어도 일부 변환이 필요합니다.컴퓨터는 Big vs Little Endian, 네트워크 바이트 순서, 패킷화, 세션 정보 등을 고려해야 합니다.

메흐드라드의 올바른 답변이 효과가 있다는 것을 보여주기 위해, 그의 접근법은 이 없는 대리 캐릭터(많은 사람들이 나의 답변에 반대했지만, 모든 사람이 똑같이 죄를 지었습니다.System.Text.Encoding.UTF8.GetBytes,System.Text.Encoding.Unicode.GetBytes으로는 상위 수 . 즉, 상위 대리 문자를 유지할 수 없습니다.d800 상위 를 값인 "예", "예", "예", "예", "예", "예", "예", "예", "예"로.fffd

using System;

class Program
{     
    static void Main(string[] args)
    {
        string t = "爱虫";            
        string s = "Test\ud800Test"; 

        byte[] dumpToBytes = GetBytes(s);
        string getItBack = GetString(dumpToBytes);

        foreach (char item in getItBack)
        {
            Console.WriteLine("{0} {1}", item, ((ushort)item).ToString("x"));
        }    
    }

    static byte[] GetBytes(string str)
    {
        byte[] bytes = new byte[str.Length * sizeof(char)];
        System.Buffer.BlockCopy(str.ToCharArray(), 0, bytes, 0, bytes.Length);
        return bytes;
    }

    static string GetString(byte[] bytes)
    {
        char[] chars = new char[bytes.Length / sizeof(char)];
        System.Buffer.BlockCopy(bytes, 0, chars, 0, bytes.Length);
        return new string(chars);
    }        
}

출력:

T 54
e 65
s 73
t 74
? d800
T 54
e 65
s 73
t 74

이 기능을 시스템에서 사용해 보십시오.Text. 부호화 중.UTF8.GetBytes 또는 시스템.Text. 부호화 중.유니코드GetBytes. 상위 대리 문자를 값 fffd로 대체하기만 하면 됩니다.

이 질문에서 움직임이 있을 때마다 페어링되지 않은 대리 문자가 포함된 문자열도 유지할 수 있는 시리얼라이저(Microsoft 또는 서드파티제의 컴포넌트)를 생각하고 있습니다.시리얼라이즈에는 때때로 페어링되지 않은 대리 문자가 포함되어 있습니다.NET. 이게 잠을 못 자게 하는 건 아니지만누군가 가끔 제 대답에 대해 결점이 있다고 코멘트하는 게 좀 짜증나지만 짝이 없는 대리모 캐릭터에 대해서는 똑같이 결점이 있습니다.

에서는 「」를 사용하고 것입니다.System.Buffer.BlockCopy BinaryFormatter

谢谢!

코드보다 훨씬 적은 코드를 사용해 보십시오.

System.Text.Encoding.UTF8.GetBytes("TEST String");

음, 제가 모든 답을 읽어봤는데 암호나 짝이 없는 대리인을 떨어뜨리는 연쇄반응에 관한 거였어요

예를 들어 문자열이 암호 해시를 저장하는 바이트 배열에서 작성된 SQL Server에서 가져온 경우 문제가 발생합니다.여기서 삭제하면 비활성 해시가 저장되고 XML에 저장할 경우 그대로 둡니다(XML 라이터가 페어링되지 않은 대리모에 대한 예외를 삭제하기 때문입니다).

이 경우 바이트 배열의 Base64 인코딩을 사용합니다만, 인터넷에서는 C#에 해결책이 1개밖에 없습니다.또한 버그가 포함되어 있기 때문에 버그를 수정하고 되돌리기 절차를 기술했습니다.여기 있습니다, 미래의 구글러 여러분:

public static byte[] StringToBytes(string str)
{
    byte[] data = new byte[str.Length * 2];
    for (int i = 0; i < str.Length; ++i)
    {
        char ch = str[i];
        data[i * 2] = (byte)(ch & 0xFF);
        data[i * 2 + 1] = (byte)((ch & 0xFF00) >> 8);
    }

    return data;
}

public static string StringFromBytes(byte[] arr)
{
    char[] ch = new char[arr.Length / 2];
    for (int i = 0; i < ch.Length; ++i)
    {
        ch[i] = (char)((int)arr[i * 2] + (((int)arr[i * 2 + 1]) << 8));
    }
    return new String(ch);
}

또, 부호화를 고려해야 하는 이유에 대해서도 설명해 주세요.문자열이 저장되어 있는 바이트를 간단하게 얻을 수 없습니까?왜 이렇게 인코딩에 의존합니까?!!

"문자열의 바이트" 같은 것은 존재하지 않기 때문입니다.

문자열(또는 일반적으로 텍스트)은 문자, 숫자 및 기타 기호로 구성됩니다.그게 다예요.그러나 컴퓨터는 문자에 대해 아무것도 모르고 바이트만 처리할 수 있습니다.따라서 컴퓨터를 사용하여 텍스트를 저장하거나 전송하려면 문자를 바이트로 변환해야 합니다.어떻게 하는 거야?여기서 암호화가 이루어집니다.

부호화는 논리 문자를 물리 바이트로 변환하는 규칙에 불과합니다.가장 간단하고 잘 알려진 인코딩은 ASCII입니다.영어로 쓰면 됩니다.다른 언어의 경우 Unicode의 맛을 가장 안전하게 선택할 수 있도록 보다 완전한 인코딩이 필요합니다.

즉, "인코딩을 사용하지 않고 문자열의 바이트를 얻으려고 하는 것"은 "언어를 사용하지 않고 텍스트를 쓰는 것"만큼 불가능합니다.

덧붙여서, 저는 여러분(그리고 그 점에 대해서는 누구라도)에게 이 작은 지혜를 읽어보라고 강력히 권합니다.모든 소프트웨어 개발자는 Unicode와 문자 집합에 대해 절대적으로 알아야 합니다(변명 없음).

하는 C#string a까지byte 스위칭:

public static byte[] StrToByteArray(string str)
{
   System.Text.UTF8Encoding  encoding=new System.Text.UTF8Encoding();
   return encoding.GetBytes(str);
}
byte[] strToByteArray(string str)
{
    System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
    return enc.GetBytes(str);
}

C# 7.2와 함께 릴리즈된 에서는 스트링의 기본 메모리 표현을 관리 대상 바이트 배열로 캡처하는 표준 기술은 다음과 같습니다.

byte[] bytes = "rubbish_\u9999_string".AsSpan().AsBytes().ToArray();

데이터를 다시 변환하는 것은 사실상 데이터를 어떤 식으로든 해석하고 있다는 것을 의미하지만, 완전성을 위해 데이터를 다시 변환하는 것은 쉽지 않습니다.

string s;
unsafe
{
    fixed (char* f = &bytes.AsSpan().NonPortableCast<byte, char>().DangerousGetPinnableReference())
    {
        s = new string(f);
    }
}

★★NonPortableCast ★★★★★★★★★★★★★★★★★」DangerousGetPinnableReference이런 짓을 하면 안 된다는 주장을 더 펼치면 안 돼요

「 」로 에 주의해 .Span<T>사용하려면 시스템을 설치해야 합니다.메모리 NuGet 패키지

그럼에도 불구하고, 실제 원래의 질문과 후속 코멘트는 기본 메모리가 "해석"되지 않았음을 암시합니다(이러한 수단은 그대로 쓰기의 필요 이상으로 수정되거나 읽히지 않았음을 가정함). 이는 일부 구현이 있음을 나타냅니다.Stream데이터를 문자열로 추론하는 대신 클래스를 사용해야 합니다.

문자열과 바이트 배열 간의 변환에 다음 코드를 사용할 수 있습니다.

string s = "Hello World";

// String to Byte[]

byte[] byte1 = System.Text.Encoding.Default.GetBytes(s);

// OR

byte[] byte2 = System.Text.ASCIIEncoding.Default.GetBytes(s);

// Byte[] to string

string str = System.Text.Encoding.UTF8.GetString(byte1);

확실하지는 않지만 문자열은 정보를 문자 배열로 저장하기 때문에 바이트 단위로 비효율적입니다.구체적으로 Char의 정의는 "Unicode 문자를 나타냅니다"입니다.

다음 예를 들어 보겠습니다.

String str = "asdf éß";
String str2 = "asdf gh";
EncodingInfo[] info =  Encoding.GetEncodings();
foreach (EncodingInfo enc in info)
{
    System.Console.WriteLine(enc.Name + " - " 
      + enc.GetEncoding().GetByteCount(str)
      + enc.GetEncoding().GetByteCount(str2));
}

Unicode 응답은 두 경우 모두 14바이트인데 반해 UTF-8 응답은 첫 번째가 9바이트, 두 번째가 7바이트에 불과하다는 점에 유의하십시오.

문자열에서 사용할 " " "를 사용하십시오.Encoding.Unicode그러나 스토리지 공간에서는 비효율적입니다.

중요한 문제는 문자열의 글리프는 32비트(문자 코드의 경우 16비트)가 소요되지만 바이트에는 8비트밖에 여유가 없다는 것입니다.ASCII 문자만 포함하는 문자열로 제한하지 않는 한 일대일 매핑은 존재하지 않습니다.시스템.Text.Encoding에는 문자열을 바이트[]에 매핑하는 방법이 많이 있습니다.정보 손실을 방지하고 클라이언트가 바이트[]를 문자열에 매핑해야 할 때 사용하기 쉬운 것을 선택해야 합니다.

Utf8은 일반적인 인코딩으로, 콤팩트하고 손실되지 않습니다.

용도:

    string text = "string";
    byte[] array = System.Text.Encoding.UTF8.GetBytes(text);

결과는 다음과 같습니다.

[0] = 115
[1] = 116
[2] = 114
[3] = 105
[4] = 110
[5] = 103

가장 빠른 방법

public static byte[] GetBytes(string text)
{
    return System.Text.ASCIIEncoding.UTF8.GetBytes(text);
}

Makotosan 님의 코멘트로 편집이 최선의 방법입니다.

Encoding.UTF8.GetBytes(text)

OP의 질문에 가장 가까운 접근법은 Tom Blodget으로, 실제로 오브젝트에 들어가 바이트를 추출합니다.String Object의 구현에 따라 다르기 때문에 가장 가깝다고 말합니다.

"Can't I simply get what bytes the string has been stored in?"

네, 하지만 여기서 근본적인 오류가 발생합니다.String은 대상 데이터 구조를 가질 수 있는 개체입니다.우린 이미 알고 있어요 짝이 없는 대리인들을 보관할 수 있으니까요길이가 저장될 수 있습니다.각각의 '쌍' 대리인에 대한 포인터를 유지하여 빠르게 계산할 수 있게 할 수도 있습니다.기타. 이러한 추가 바이트는 모두 문자 데이터의 일부가 아닙니다.

원하는 것은 배열 내의 각 문자의 바이트입니다.여기서 '인코딩'이 등장합니다.디폴트로는 UTF-16LE가 됩니다.라운드 트립 이외의 바이트 자체에 관심이 없는 경우 디폴트를 포함한 임의의 인코딩을 선택하고 나중에 변환할 수 있습니다(기본 인코딩, 코드 포인트, 버그 수정, 페어링되지 않은 대용품 등 허용되는 동일한 파라미터가 있다고 가정).

하지만 왜 '인코딩'을 마법에 맡길까요?어떤 바이트를 얻을 수 있는지 알 수 있도록 인코딩을 지정하는 것은 어떨까요?

"Why is there a dependency on character encodings?"

(이 컨텍스트에서) 부호화는 단순히 문자열을 나타내는 바이트를 의미합니다.문자열 개체의 바이트가 아닙니다.문자열이 저장된 바이트를 원하는 경우 - 여기서 질문이 순진하게 질문됩니다.문자열 객체가 포함할 수 있는 다른 모든 이진 데이터가 아니라 문자열을 나타내는 연속 배열의 문자열 바이트를 사용하려고 했습니다.

즉, 문자열이 저장되는 방식은 관련이 없습니다.바이트 배열에서 "Encoded" 문자열을 바이트로 만들어야 합니다.

나는 Tom Bloget의 대답이 마음에 든다. 왜냐하면 그는 당신을 '문자열 객체의 바이트' 방향으로 안내했기 때문이다.구현에 따라 다르긴 하지만, 그가 내부를 훔쳐보고 있기 때문에 문자열의 복사본을 재구성하는 것은 어려울 수 있습니다.

Mehrdad의 답변은 개념적인 수준에서 오해를 불러일으키기 때문에 잘못되었다.이치노그의 특정 솔루션은 짝을 이루지 않은 대리인을 보존할 수 있도록 합니다. 이것은 구현에 의존합니다.의 특정 .GetBytesUTF-8을 사용합니다.


이 (Mehrdad의 솔루션)에 대해 생각을 바꿨습니다.이것은 문자열의 바이트를 얻는 것이 아니라 문자열에서 생성된 문자 배열의 바이트를 얻는 것입니다.부호화에 관계없이 c#의 문자 데이터형은 고정 크기입니다.이를 통해 일관된 길이의 바이트 배열을 생성할 수 있으며 바이트 배열의 크기에 따라 문자 배열을 복제할 수 있습니다.따라서 인코딩이 UTF-8이지만 각 문자가 최대 utf8 값을 수용하기 위해6 바이트인 경우에도 동작합니다.문자 인코딩은 문제가 되지 않습니다.

그러나 변환이 사용되었습니다.각 문자를 고정 크기 상자(c#의 문자 유형)에 넣습니다.그러나 그 표현이 무엇인지는 중요하지 않습니다. 엄밀히 말하면 OP에 대한 답변입니다.그러니까, 어쨌든 변환하는 거라면...왜 'encode'를 하지 않는가?

에서 문자열을 바이트[]로 변환하려면 어떻게 해야 하나요?특정 인코딩을 수동으로 지정하지 않고 NET(C#)을 사용할 수 있습니까?

의 문자열.NET은 텍스트를 UTF-16 코드 유닛의 시퀀스로 나타내므로 바이트는 이미 UTF-16의 메모리에 부호화되어 있습니다.

메흐르다드의 대답

Mehrdad의 답변을 사용할 수 있지만 문자가 UTF-16이기 때문에 실제로는 인코딩을 사용합니다.ToCharArray를 호출하여 소스를 조사하면char[]메모리에 직접 카피합니다.그런 다음 할당된 바이트 배열에 데이터를 복사합니다.따라서 후드 아래에서는 기본 바이트를 두 번 복사하고 콜 후에 사용되지 않는 char 배열을 할당합니다.

톰 블로젯의 대답

Tom Blodget의 답변은 Mehrdad보다 20-30% 빠릅니다.이것은 char 어레이를 할당하고 바이트를 복사하는 중간 단계를 건너뛰기 때문입니다.다만, 이 경우,/unsafe 것이 생각합니다.인코딩을 사용하고 싶지 않다면 이 방법이 좋을 것 같습니다.을 「」에 .fixed별도의 바이트 배열을 할당하여 바이트를 복사할 필요도 없습니다.

또한 인코딩을 고려해야 하는 이유는 무엇입니까?문자열이 저장되어 있는 바이트를 간단하게 얻을 수 없습니까?문자 인코딩에 의존하는 이유는 무엇입니까?

왜냐하면 그것이 그것을 하는 올바른 방법이기 때문이다. string상화입입니니다

잘못된 문자의 문자열이 있는 경우 인코딩을 사용하면 문제가 발생할 수 있지만, 이 경우 문제가 발생하지 않습니다.잘못된 문자로 데이터를 문자열에 가져오는 경우 잘못된 것입니다.처음에는 바이트 배열 또는 Base64 인코딩을 사용해야 합니다.

「 」를 사용하고 System.Text.Encoding.Unicode코드 복원력이 향상됩니다.코드가 실행되는 시스템의 엔디안성에 대해 걱정할 필요는 없습니다.다음 버전의 CLR에서 다른 내부 문자 인코딩이 사용되는지는 걱정할 필요가 없습니다.

문제는 왜 인코딩을 걱정하느냐가 아니라 왜 그것을 무시하고 다른 것을 사용하느냐는 것이라고 생각합니다.부호화는 일련의 바이트에서 문자열의 추상화를 나타내는 것을 의미합니다. System.Text.Encoding.Unicode그럼 엔디안 바이트 순서 인코딩이 약간 제공되며 현재와 미래의 모든 시스템에서 동일하게 수행됩니다.

하여 a를 할 수 .string a까지byte array.네트워크

string s_unicode = "abcéabc";
byte[] utf8Bytes = System.Text.Encoding.UTF8.GetBytes(s_unicode);

문자열의 기본 바이트 복사본을 원하는 경우 다음과 같은 함수를 사용할 수 있습니다.하지만, 그 이유를 알기 위해 계속 읽어서는 안 됩니다.

[DllImport(
        "msvcrt.dll",
        EntryPoint = "memcpy",
        CallingConvention = CallingConvention.Cdecl,
        SetLastError = false)]
private static extern unsafe void* UnsafeMemoryCopy(
    void* destination,
    void* source,
    uint count);

public static byte[] GetUnderlyingBytes(string source)
{
    var length = source.Length * sizeof(char);
    var result = new byte[length];
    unsafe
    {
        fixed (char* firstSourceChar = source)
        fixed (byte* firstDestination = result)
        {
            var firstSource = (byte*)firstSourceChar;
            UnsafeMemoryCopy(
                firstDestination,
                firstSource,
                (uint)length);
        }
    }

    return result;
}

이 함수는 문자열의 기초가 되는 바이트 복사본을 매우 빠르게 가져옵니다.이러한 바이트는 시스템에서 인코딩되는 방식에 관계없이 얻을 수 있습니다.이 인코딩은 거의 확실히 UTF-16LE이지만, 실장에 대해서는 신경 쓸 필요가 없습니다.

그냥 전화하는 게 더 안전하고,간단하고, 더 신뢰할 수 있을 거야

System.Text.Encoding.Unicode.GetBytes()

이것은 거의 같은 결과를 얻을 수 있고 입력이 용이하며 바이트는 라운드 트립할 뿐만 아니라 Unicode로 바이트 표현도 할 수 있습니다.

System.Text.Encoding.Unicode.GetString()

하지 않은 이다.String로로 합니다.Byte[]★★★★

public static unsafe Byte[] GetBytes(String s)
{
    Int32 length = s.Length * sizeof(Char);
    Byte[] bytes = new Byte[length];

    fixed (Char* pInput = s)
    fixed (Byte* pBytes = bytes)
    {
        Byte* source = (Byte*)pInput;
        Byte* destination = pBytes;

        if (length >= 16)
        {
            do
            {
                *((Int64*)destination) = *((Int64*)source);
                *((Int64*)(destination + 8)) = *((Int64*)(source + 8));

                source += 16;
                destination += 16;
            }
            while ((length -= 16) >= 16);
        }

        if (length > 0)
        {
            if ((length & 8) != 0)
            {
                *((Int64*)destination) = *((Int64*)source);

                source += 8;
                destination += 8;
            }

            if ((length & 4) != 0)
            {
                *((Int32*)destination) = *((Int32*)source);

                source += 4;
                destination += 4;
            }

            if ((length & 2) != 0)
            {
                *((Int16*)destination) = *((Int16*)source);

                source += 2;
                destination += 2;
            }

            if ((length & 1) != 0)
            {
                ++source;
                ++destination;

                destination[0] = source[0];
            }
        }
    }

    return bytes;
}

비록 우아하지는 않더라도, 인정받는 앤서보다 훨씬 빠릅니다.10000,000회 이상의 Stopwatch 벤치마크를 다음에 나타냅니다.

[Second String: Length 20]
Buffer.BlockCopy: 746ms
Unsafe: 557ms

[Second String: Length 50]
Buffer.BlockCopy: 861ms
Unsafe: 753ms

[Third String: Length 100]
Buffer.BlockCopy: 1250ms
Unsafe: 1063ms

사용하려면 프로젝트 빌드 속성에서 "안전하지 않은 코드 허용"을 선택해야 합니다.에 따라서.NET Framework 3.5, 이 메서드는 String 확장으로도 사용할 수 있습니다.

public static unsafe class StringExtensions
{
    public static Byte[] ToByteArray(this String s)
    {
        // Method Code
    }
}

바이트를 사용하여 무엇을 할 것인지를 묻는 질문에 다음과 같이 대답했습니다.

암호화할 거야변환하지 않고 암호화할 수 있지만, 여기서 인코딩이 재생되는 이유를 알고 싶습니다.그냥 바이트만 줘. 내가 말하는 거야.

이 암호화된 데이터를 네트워크를 통해 전송할지, 나중에 메모리에 다시 로드할지, 아니면 다른 프로세스로 스트리밍할지 여부에 관계없이 어떤 시점에서 암호를 해독할지는 분명합니다.이 경우 정답은 통신 프로토콜을 정의하는 것입니다.통신 프로토콜은 프로그래밍 언어 및 관련 런타임의 구현 세부 정보 측면에서 정의해서는 안 됩니다.여기에는 몇 가지 이유가 있습니다.

  • 다른 언어 또는 런타임으로 구현된 프로세스와 통신할 필요가 있을 수 있습니다.(예를 들어 다른 머신에서 실행 중인 서버나 JavaScript 브라우저 클라이언트에 문자열을 보내는 서버 등이 포함됩니다).
  • 이 프로그램은 향후 다른 언어 또는 런타임으로 재실장될 수 있습니다.
  • .NET 실장에서는 문자열의 내부 표현이 변경될 수 있습니다.이것은 억지스럽게 들릴지 모르지만, 실제로는 Java 9에서 메모리 사용을 줄이기 위해 일어난 일입니다.이유가 없어요.NET은 선례를 따를 수 없었습니다.Sket은 UTF-16이 현재 최적이 아닐 수 있다는 것을 시사하고 있으며, 이는 유니코드의 이모티콘과 다른 블록들을 표현하기 위해 2바이트 이상을 필요로 하기 때문에 향후 내부 표현이 변경될 가능성을 증가시킨다.

(완전히 다른 프로세스 또는 향후 같은 프로그램과) 통신하려면 프로토콜을 엄격하게 정의하여 작업하거나 실수로 버그를 생성하는 어려움을 최소화해야 합니다.에 따라 다릅니다.NET의 내부 표현은 엄격하거나 명확하지 않으며 일관성이 보장되지도 않습니다.표준 부호화는 향후 실패하지 않는 엄밀한 정의입니다.

즉, 부호화를 지정하지 않으면 일관성 요건을 충족할 수 없습니다.

이후 프로세스의 퍼포먼스가 현저하게 향상되었을 경우 UTF-16을 직접 사용할 수도 있습니다.NET 에서는, 내부 또는 그 외의 이유로 사용되고 있습니다만, 그 부호화를 명시적으로 선택해, 에 의존하지 않고 코드로 명시적으로 변환을 실행할 필요가 있습니다.NET의 사내 실장.

따라서 인코딩을 선택하여 사용합니다.

using System.Text;

// ...

Encoding.Unicode.GetBytes("abc"); # UTF-16 little endian
Encoding.UTF8.GetBytes("abc")

보시는 바와 같이 임베디드 부호화 오브젝트만 사용하는 것이 독자/라이터 메서드를 구현하는 것보다 코드도 적습니다.

문자열은 다음과 같은 이유로 몇 가지 다른 방법으로 바이트 배열로 변환할 수 있습니다.NET은 Unicode를 지원하며 Unicode는 UTF라고 불리는 몇 가지 차분 인코딩을 표준화합니다.바이트 표현 길이는 다르지만 스트링이 부호화되면 스트링에 다시 부호화할 수 있지만 스트링이 하나의 UTF로 부호화되어 다른 UTF로 디코딩될 경우 를 망칠 수 있다는 가정 하에 디코딩될 수 있습니다.

또한 .NET은 비 Unicode 인코딩을 지원하지만 일반적으로는 유효하지 않습니다(ASCII 등의 실제 문자열에서 Unicode 코드 포인트의 제한된 서브셋이 사용되는 경우에만 유효합니다).내부적으로는,NET은 UTF-16을 지원하지만 스트림 표현에는 보통 UTF-8이 사용됩니다.그것은 또한 인터넷의 표준적인 사실이기도 하다.

도 없이 배열로의 및 역직렬화는 「」에서 서포트되고 있습니다System.Text.Encoding인 인코딩을ASCIIEncoding의 UTF4' UTF')System.Text.UnicodeEncoding UTF-16)를 지원합니다.

링크를 참조합니다.

를 사용하여 :System.Text.Encoding.GetBytes는, 「」를 사용합니다.System.Text.Encoding.GetCharsSystem.String(char[]).
이 페이지를 참조해 주세요.

예:

string myString = //... some string

System.Text.Encoding encoding = System.Text.Encoding.UTF8; //or some other, but prefer some UTF is Unicode is used
byte[] bytes = encoding.GetBytes(myString);

//next lines are written in response to a follow-up questions:

myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);
myString = new string(encoding.GetChars(bytes));
byte[] bytes = encoding.GetBytes(myString);

//how many times shall I repeat it to show there is a round-trip? :-)

원하는 바이트의 용도에 따라 달라집니다.

왜냐하면, 타일러가 적절하게 말했듯이, "스트링은 순수한 데이터가 아닙니다.정보도 있습니다.이 경우 정보는 문자열 작성 시 상정된 부호화입니다.

문자열에 저장된 (텍스트가 아닌) 이항 데이터가 있다고 가정합니다.

이것은 OP의 자신의 질문에 대한 코멘트를 바탕으로 한 것으로, OP의 사용 예에 대한 힌트를 이해하면 맞는 질문입니다.

위에서 설명한 인코딩이 가정되었기 때문에 이진 데이터를 문자열에 저장하는 것은 잘못된 접근 방식일 수 있습니다.string)byte[](어레이가 더 적절했을 텐데)가 시작도 하기 전에 이미 싸움에서 졌습니다.REST 요구/응답 또는 스트링을 전송해야 하는 어떤 방법으로든 바이트를 송신하고 있다면 Base64가 적절한 접근법입니다.

알 수 없는 인코딩을 가진 텍스트 문자열이 있는 경우

다른 사람들은 모두 이 틀린 문제에 잘못 답했어요.

이 그대로하게 표시되는 는, 하면 UTF 로 하는 부호화)를.하는 「」( 「UTF」)를 합니다.System.Text.Encoding.???.GetBytes()어떤 인코딩을 선택했는지 바이트를 제공하는 사용자에게 알립니다.

사용하고 있는 경우.NET Core 또는 시스템의 메모리.NET Framework는 스팬메모리를 통해 매우 효율적인 마샬링 메커니즘을 이용할 수 있습니다.문자열 메모리를 바이트 범위로 효과적으로 재해석할 수 있습니다.바이트 스팬이 있으면 다른 타입으로 다시 정리하거나 어레이에 복사하여 시리얼화할 수 있습니다.

다른 사람의 의견을 요약하면 다음과 같습니다.

  • 이런 종류의 시리얼라이제이션 표현을 저장하는 것은 시스템엔디안성, 컴파일러 최적화 및 실행 문자열 내부 표현의 변경에 영향을 받습니다.NET ★★★
    • 장기 보관 방지
    • 른른른 른른 른 츠키노
      • 여기에는 다른 머신, 프로세서 아키텍처 등이 포함됩니다.NET 런타임, 컨테이너 등
      • 여기에는 비교, 포맷, 암호화, 문자열 조작, 현지화, 문자 변환 등이 포함됩니다.
    • 문자 인코딩에 대한 추측을 피합니다.
      • 디폴트 인코딩은 실제로는 UTF-16LE이지만 컴파일러/런타임이 내부 표현을 선택할 수 있습니다.

실행

public static class MarshalExtensions
{
   public static ReadOnlySpan<byte> AsBytes(this string value) => MemoryMarshal.AsBytes(value.AsSpan());
   public static string AsString(this ReadOnlySpan<byte> value) => new string(MemoryMarshal.Cast<byte, char>(value));
}

static void Main(string[] args)
{
    string str1 = "你好,世界";
    ReadOnlySpan<byte> span = str1.AsBytes();
    string str2 = span.AsString();

    byte[] bytes = span.ToArray();

    Debug.Assert(bytes.Length > 0);
    Debug.Assert(str1 == str2);
}

퍼튜어 인사이트

C++에서는 이것은 refret_cast와 거의 동등하며, C에서는 시스템의 단어 유형(char)에 대한 캐스트와 거의 동등합니다.

최신 버전.NET Core Runtime(CoreCLR), 스팬에 대한 연산은 컴파일러의 내장 함수 및 다양한 최적화를 효과적으로 호출합니다.이것에 의해, 때때로 경계 체크가 불필요해지기 때문에, 메모리의 안전성을 유지하면서 뛰어난 퍼포먼스를 얻을 수 있습니다.메모리가 CLR에 의해 할당되고 스팬이 관리되지 않는 메모리 할당자에서 포인터에서 파생되지 않았다고 가정합니다.

주의사항

이 방법에서는 문자열에서 Read Only Span <char>을 반환하는 CLR에서 지원되는 메커니즘을 사용합니다.또, 이 스팬에 반드시 내부 스트링 레이아웃 전체가 포함되는 것은 아닙니다.읽기 전용 범위 <문자열은 불변하기 때문에 변환을 실행할 필요가 있는 경우 복사본을 작성해야 함을 나타냅니다.

컴퓨터는 원시 바이너리 데이터, 원시 비트만 인식합니다.1비트는 0 또는 1의 이진수입니다.8비트 숫자는 바이트입니다.1 바이트는 0 ~255 사이의 숫자입니다.

ASCII는 숫자를 문자로 변환하는 테이블입니다.0 ~ 31 의 숫자는, 탭, 새로운 행등의 컨트롤입니다.32 ~ 126 의 숫자는 인쇄 가능한 문자입니다.문자 a, 숫자 1, % 기호, 밑줄 _

ASCII에서는 33개의 컨트롤 문자와 95개의 인쇄 가능한 문자가 있습니다.

ASCII는 현재 가장 일반적으로 사용되는 문자 인코딩입니다.Unicode 테이블의 첫 번째 엔트리는 ASCII이며 ASCII 문자 세트와 일치합니다.

ASCII는 7비트 문자 세트입니다.0 ~ 127 의 숫자입니다.8비트를 사용하면 최대 255비트를 사용할 수 있습니다.

ASCII에 대한 가장 일반적인 대체 방법은 ASCII와 호환되지 않는 EBCDIC으로, 현재도 IBM 컴퓨터와 데이터베이스에 존재합니다.

1바이트, 그래서 8비트 숫자는 요즘 컴퓨터 공학에서 가장 일반적인 단위입니다.1 바이트는 0 ~255 사이의 숫자입니다.

ASCII 는, 0 ~127 의 각 번호에 대한 의미를 정의합니다.

128 ~ 255 의 숫자에 관련 붙여진 문자는, 사용하는 문자 인코딩에 의해서 다릅니다.현재 널리 사용되는 2개의 문자 인코딩은 windows1252와 UTF-8입니다.

Windows 1252에서 € 기호에 해당하는 숫자는 128.1 바이트 : [A0]입니다.Unicode 데이터베이스에서 € 기호는 8364입니다.

이제 8364라는 번호를 드리겠습니다.토우바이트 : [20, AC]UTF-8의 유로 기호는 14844588입니다.3 바이트 : [E282AC]

이제 원시 데이터를 몇 가지 드리겠습니다.20AC로 합시다.Windows 1252 문자 2개입니까? £ 또는 Unicode € 기호 1개입니까?

미가공 데이터를 더 드리겠습니다.E282AC.Windows 1252에서는 82는 할당되지 않은 문자이므로 Windows 1252는 아닐 것입니다.macRoman "‚¨"" 또는 OEM 437 "éó"" 또는 UTF-8 " """ 기호일 수 있습니다.

문자 인코딩의 특성과 통계 정보를 바탕으로 원시 바이트 스트림의 인코딩을 추측할 수 있지만 신뢰할 수 있는 방법은 없습니다.UTF-8에서는 128 ~255 의 번호 자체는 무효입니다.é는 일부 언어(프랑스어)에서 일반적이기 때문에 값 E9이 문자로 둘러싸인 바이트가 많을 경우 아마도 Windows1252 인코딩 문자열(E9 바이트는 é 문자를 나타냄)일 것입니다.

문자열을 나타내는 원시 바이트의 스트림이 있는 경우 추측을 시도하는 것보다 일치하는 인코딩을 알아두는 것이 훨씬 좋습니다.

다음은 한 때 널리 사용되었던 다양한 인코딩의 1개의 원시 바이트 스크린샷입니다.

다양한 인코딩으로 표시되는 1바이트 문자

두 가지 방법:

public static byte[] StrToByteArray(this string s)
{
    List<byte> value = new List<byte>();
    foreach (char c in s.ToCharArray())
        value.Add(c.ToByte());
    return value.ToArray();
}

그리고.

public static byte[] StrToByteArray(this string s)
{
    s = s.Replace(" ", string.Empty);
    byte[] buffer = new byte[s.Length / 2];
    for (int i = 0; i < s.Length; i += 2)
        buffer[i / 2] = (byte)Convert.ToByte(s.Substring(i, 2), 16);
    return buffer;
}

저는 위보다 아래 쪽을 더 자주 사용하는 편이에요.속도를 벤치마킹한 적은 없어요.

언급URL : https://stackoverflow.com/questions/472906/how-do-i-get-a-consistent-byte-representation-of-strings-in-c-sharp-without-manu

반응형