[C#] 이 문자열의 길이가 문자 수보다 긴 이유는 무엇입니까?

이 코드는 :

string a = "abc";
string b = "A?C";
Console.WriteLine("Length a = {0}", a.Length);
Console.WriteLine("Length b = {0}", b.Length);

출력 :

Length a = 3
Length b = 4

왜? 내가 상상할 수있는 유일한 것은 한자가 2 바이트 길이이고 .Length메소드가 바이트 수를 반환한다는 것입니다.



답변

다른 모든 사람들은 표면적 해답을 제시하지만 더 깊은 근거도 있습니다. “문자”의 수는 정의하기 어려운 질문이며 놀랍게도 계산 비용이 많이 들지만 길이 속성은 빠릅니다.

정의하기 어려운 이유는 무엇입니까? 글쎄, 몇 가지 옵션이 있으며 다른 옵션보다 더 유효한 것은 없습니다.

  • 코드 단위의 수 (바이트 또는 기타 고정 크기 데이터 청크; C # 및 Windows는 일반적으로 UTF-16을 사용하므로 2 바이트 수를 반환 함)는 컴퓨터가 여전히 해당 형식의 데이터를 처리해야하므로 관련성이 있습니다. 많은 목적을 위해 (예를 들어, 파일에 쓰는 것은 문자가 아닌 바이트를 고려합니다)

  • 유니 코드 코드 포인트의 수는 계산하기가 쉬우 며 (대리 쌍을 위해 문자열을 스캔해야하기 때문에 O (n)이지만) 텍스트 편집기에는 중요 할 수 있지만 실제로는 문자 수와 동일하지 않습니다. 화면에 인쇄됩니다 (graphemes). 예를 들어, 일부 악센트 문자는 두 가지 형식으로 표시 될 수 있습니다. 단일 코드 포인트 또는 서로 짝을 이루는 두 점 (문자를 나타내는 문자 및 “내 파트너 문자에 악센트 추가”). 쌍이 두 문자 또는 하나입니까? 이를 돕기 위해 문자열을 정규화 할 수 있지만 모든 유효한 문자에 단일 코드 포인트 표현이있는 것은 아닙니다.

  • grapheme의 수조차도 다른 요인들 중 글꼴에 따라 인쇄 문자열의 길이와 동일하지 않으며 일부 문자는 많은 글꼴 (커닝)에서 일부 겹침으로 인쇄되기 때문에 화면의 문자열 길이 그래도 그래 핀 길이의 합과 반드시 ​​같을 필요는 없습니다!

  • 일부 유니 코드 포인트는 전통적인 의미의 문자가 아니라 일종의 제어 마커입니다. 바이트 순서 마커 또는 오른쪽에서 왼쪽으로 표시기와 같습니다. 이것도 중요합니까?

간단히 말해서, 문자열의 길이는 실제로 엄청나게 복잡한 질문이며 계산하는 데 데이터 테이블뿐만 아니라 많은 CPU 시간이 걸릴 수 있습니다.

게다가 요점이 뭐야? 이러한 측정 항목이 중요한 이유 글쎄, 오직 당신 만이 당신의 사건에 대해 대답 할 수 있지만 개인적으로 나는 그것들이 일반적으로 관련이 없다는 것을 알았습니다. 내가 찾은 데이터 입력 제한은 바이트 제한에 의해보다 논리적으로 수행됩니다. 어쨌든 전송하거나 저장해야하기 때문입니다. 메시지 크기가 100 픽셀 인 경우 적합한 문자 수는 데이터 계층 소프트웨어에서 알려지지 않은 글꼴 등에 따라 다릅니다. 마지막으로, 유니 코드 표준의 복잡성을 감안할 때 다른 방법을 시도하면 어쩌면 가장자리에 버그가있을 수 있습니다.

따라서 범용 용도가 많지 않은 어려운 질문입니다. 코드 단위의 수는 계산하기가 쉽지 않습니다. 기본 데이터 배열의 길이 일 뿐이며 간단한 정의로 일반적인 규칙으로 가장 의미 있고 유용합니다.

그렇기 때문에 “문서가 그렇게 말했기 때문에”이라는 표면적 설명을 넘어선 b길이 4입니다.


답변

속성 의 문서 에서 String.Length:

Length 속성은 이 인스턴스에서 유니 코드 문자 수가 아닌 Char 객체 수를 반환합니다 . 그 이유는 유니 코드 문자가 둘 이상의 Char 로 표시 될 수 있기 때문입니다 . 각 Char 대신 각 유니 코드 문자로 작업 하려면 System.Globalization.StringInfo 클래스를 사용하십시오 .


답변

색인 1의 캐릭터 "A?C"SurrogatePair입니다.

기억해야 할 요점은 서로 게이트 쌍이 32 비트
단일 문자를 나타냅니다 .

이 코드를 시도하면 반환됩니다 True

Console.WriteLine(char.IsSurrogatePair("A?C", 1));

Char.IsSurrogatePair 메서드 (String, Int32)

trues 매개 변수가 index 및 index + 1 위치에 인접한 문자를 포함 하고 위치 인덱스 에있는 문자의 숫자 값이 U + D800-U + DBFF 범위이고, index + 1 위치에있는 문자의 숫자 값이 U 범위 인 경우 + DC00 내지 U + DFFF; 그렇지 않으면 false.

이것은 String.Length 속성 에서 더 설명됩니다 .

Length 속성은 이 인스턴스에서 유니 코드 문자 수가 아닌 Char 객체 수를 반환합니다 . 그 이유는 유니 코드 문자가 둘 이상의 Char로 표시 될 수 있기 때문입니다. 각 Char 대신 각 유니 코드 문자로 작업하려면 System.Globalization.StringInfo 클래스를 사용하십시오.


답변

다른 답변에서 지적했듯이 3 개의 보이는 문자가 있어도 4 개의 char객체 로 표시 됩니다. 이것이 Length3이 아닌 4 인 이유 입니다.

MSDN은

Length 속성은이 인스턴스에서 유니 코드 문자 수가 아닌 Char 객체 수를 반환합니다.

그러나 실제로 알고 싶은 것이 “텍스트 요소”의 수이고 Char객체 의 수가 아니라면 StringInfo클래스를 사용할 수 있습니다 .

var si = new StringInfo("A?C");
Console.WriteLine(si.LengthInTextElements); // 3

다음과 같이 각 텍스트 요소를 열거 할 수도 있습니다.

var enumerator = StringInfo.GetTextElementEnumerator("A?C");
while(enumerator.MoveNext()){
    Console.WriteLine(enumerator.Current);
}

foreach문자열을 사용 하면 중간 “글자”가 두 char개체로 분할 되고 인쇄 된 결과가 문자열과 일치하지 않습니다.


답변

Length속성 이 유니 코드 문자 수가 아닌 char 객체 수를 반환 하기 때문 입니다. 귀하의 경우, 유니 코드 문자 중 하나는 둘 이상의 char 객체 (SurrogatePair)로 표현됩니다.

Length 속성은이 인스턴스에서 유니 코드 문자 수가 아닌 Char 객체 수를 반환합니다. 그 이유는 유니 코드 문자가 둘 이상의 Char로 표시 될 수 있기 때문입니다. 각 Char 대신 각 유니 코드 문자로 작업하려면 System.Globalization.StringInfo 클래스를 사용하십시오.


답변

다른 사람들이 말했듯이 문자열의 문자 수가 아니라 Char 객체의 수입니다. 문자 ?는 코드 포인트 U + 20213입니다. 값이 16 비트 char 유형의 범위를 벗어나므로 surrogate 쌍으로 UTF-16으로 인코딩됩니다 D840 DE13.

문자의 길이를 얻는 방법은 다른 답변에서 언급되었습니다. 그러나 유니 코드로 문자를 나타내는 여러 가지 방법이있을 수 있으므로주의해서 사용해야합니다. “à”는 1 자로 구성되거나 2 자로 구성 될 수 있습니다 (+ 분음 부호). 트위터 의 경우처럼 정규화가 필요할 수 있습니다 .

당신은 절대적으로 모든 소프트웨어 개발자의 절대 최소값을 읽어야합니다
.


답변

length()이보다 크지 않은 유니 코드 코드 포인트에만 작동하기 때문 U+FFFF입니다. 이 코드 포인트 세트를 BMP ( Basic Multilingual Plane )라고하며 2 바이트 만 사용합니다.

외부의 유니 코드 코드 포인트 BMP는 4 바이트 서로 게이트 쌍을 사용하여 UTF-16으로 표시됩니다.

문자 수 (3)를 올바르게 세려면 StringInfo

StringInfo b = new StringInfo("A?C");
Console.WriteLine(string.Format("Length 2 = {0}", b.LengthInTextElements));