어떤 문자가 Array.from으로 그룹화됩니까?


38

JS로 놀고 있었고 JS가 사용할 때 생성 된 배열에 추가 할 요소를 결정하는 방법을 알 수 없습니다 Array.from(). 예를 들어 다음 emoji 👍은 length두 개의 코드 포인트로 구성되어 있으므로 2의 a 를 갖지만 Array.from()이 두 코드 포인트를 하나로 취급하여 하나의 요소가있는 배열을 제공합니다.

const emoji = '👍';
console.log(Array.from(emoji)); // Output: ["👍"]

그러나 일부 다른 문자에는이 문자와 같은 두 개의 코드 포인트 षि가 있습니다 (또한 .length2가 있음). 그러나이 Array.from캐릭터를 "그룹화"하지 않고 대신 두 가지 요소를 생성합니다.

const str = 'षि';
console.log(Array.from(str)); // Output: ["ष", "ि"]

내 질문은 : 문자가 두 개의 코드 포인트로 구성되어있을 때 문자가 (예 2와 같이) 분리되거나 하나의 단일 요소로 처리되는지 여부를 결정하는 것은 무엇입니까?


5
UTF-16 대리 쌍을 살펴보십시오 ...
Jonas Wilms


1
-s : 나는 다른 행동을 가지고 Array.from의 MDN의 polyfill에 대한 우려가
엘레

1
@Ele은로만 객체를 고려합니다 length. 반복자 또는 심지어 Set그것과 작동하지 않습니다
adiga

답변:


26

Array.from먼저 인수 반복자가 있으면 인수의 반복자를 호출하려고 시도하고 문자열에 반복자가 있으므로를 호출 String.prototype[Symbol.iterator]하므로 프로토 타입 메소드의 작동 방식을 살펴 보겠습니다. 여기 사양에 설명되어 있습니다 :

  1. O하자? RequireObjectCoercible (이 값).
  2. S하자? ToString (O).
  3. CreateStringIterator (S)를 반환합니다.

찾는 것은 CreateStringIterator결국 당신을 데려갑니다 21.1.5.2.1 %StringIteratorPrototype%.next ( ).

  1. cp가되게하십시오! CodePointAt (s, 위치).
  2. resultString을 인덱스 위치에서 코드 단위로 시작하는 cp. [[CodeUnitCount]] 개의 연속 코드 단위를 포함하는 문자열 값으로 설정하십시오.
  3. O. [[StringNextIndex]]를 + cp. [[CodeUnitCount]]로 설정하십시오.
  4. CreateIterResultObject (resultString, false)를 반환합니다.

CodeUnitCount관심있는 것입니다이 숫자에서 온다. CodePointAt :

  1. 먼저 문자열 내에서 인덱스 위치의 코드 단위로 사용하십시오.
  2. cp를 숫자 값이 첫 번째 값인 코드 포인트로 지정하십시오.
  3. 첫 번째가 주요 대리 또는 후행 대리가 아닌 경우

    ㅏ. 기록을 반환하십시오 { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: false }.

  4. 먼저 후행 대리 또는 위치 + 1 = 크기 인 경우

    a. 기록을 반환하십시오 { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.

  5. 두 번째로 문자열 내에서 인덱스 위치 + 1의 코드 단위로 사용하십시오.

  6. 두 번째가 후행 대리가 아닌 경우

    ㅏ. 기록을 반환하십시오 { [[CodePoint]]: cp, [[CodeUnitCount]]: 1, [[IsUnpairedSurrogate]]: true }.

  7. cp를!로 설정하십시오. UTF16DecodeSurrogatePair (첫 번째, 두 번째).

  8. 기록을 반환하십시오 { [[CodePoint]]: cp, [[CodeUnitCount]]: 2, [[IsUnpairedSurrogate]]: false }.

Array.from따라서을 사용하여 문자열을 반복 하면 해당 문자가 서로 게이트 쌍의 시작 인 경우에만 CodeUnitCount가 2로 반환됩니다. 서로 게이트 쌍으로 해석되는 문자는 다음과 같습니다 .

이러한 작업은 0xD800 ~ 0xDBFF 범위의 숫자 값을 가진 모든 코드 단위 (유니 코드 표준에 의해 선행 대리 또는보다 공식적으로 높은 대리 코드 단위 로 정의 됨) 와 숫자 값을 가진 모든 코드 단위에 특별한 처리를 적용 합니다. 다음 규칙을 사용하여 0xDC00 ~ 0xDFFF (후미 대리로 정의되거나보다 공식적으로 저 대리 코드 단위로 정의) 범위에서 .. :

षि 대리 쌍이 아닙니다.

console.log('षि'.charCodeAt()); // First character code: 2359, or 0x937
console.log('षि'.charCodeAt(1)); // Second character code: 2367, or 0x93F

그러나 👍의 캐릭터는 다음과 같습니다.

console.log('👍'.charCodeAt()); // 55357, or 0xD83D
console.log('👍'.charCodeAt(1)); // 56397, or 0xDC4D

첫 번째 문자 코드는 '👍'16 진수로 D83D이며, 이는 0xD800 to 0xDBFF주요 대리자 의 범위 내에 있습니다. 반대로 첫 번째 문자 코드 'षि'는 훨씬 낮고 그렇지 않습니다. 따라서 'षि'분리되지만 분리 '👍'되지 않습니다.

षि두 개의 문자로 구성되어 , 데바 나가리 문자 SSA 하고 ि, 데바 나가리 모음 내가 서명 . 이 순서대로 나란히 놓이면 두 개의 개별 문자로 구성되어 있음에도 불구하고 시각적으로 단일 문자로 그래픽으로 결합됩니다.

대조적으로, 문자 코드 는 단일 글리프로 함께 사용될 👍 때만 의미가 있습니다. 다른 코드 포인트없이 코드 포인트가 포함 된 문자열을 사용하려고하면 넌센스 기호가 나타납니다.

console.log('👍'[0]);
console.log('👍'[1]);


10
나는 대부분 정확하고 유용하며 신중하게 인용 된 인용문 으로이 답변이 두 경우의 주요 차이점을 명확하게 설명하지 못한다고 생각합니다. 유니 코드 관점에서 षि실제로 는 단일 코드를 구성하기 위해 고유 한 코드 포인트 가있는 문자입니다. 글리프 ( 인간에 의해 이해되는 하나의 추상 문자). 이것은 👍코드 포인트가 대리 쌍으로 분할되어야 할만큼 충분히 높더라도 완전한 문자 인 이모 지 와 대조적 입니다. 나는 이것이 (그렇지 않으면 귀중한) 이것이 많은 대답을 도울 수 있다고 분명히 밝힌다.
코뿔소

구체적으로, 자음 ष (ṣ)과 모음 ि (i)는 음절 ष (ṣi)
Amadan에

@CertainPerformance "👍"에는 하나의 코드 포인트 만 있습니다. 이는이 답변의 용어가 잘못되었음을 나타냅니다.
벤 애스턴

13

UTF-16 (js의 문자열에 사용되는 인코딩)은 16 비트 단위를 사용합니다. 따라서 15 비트를 사용하여 표현할 수있는 모든 유니 코드는 하나의 코드 포인트로 표현되며 다른 모든 것은 2로 표시되며 서로 게이트 쌍이라고 합니다. 문자열의 반복자는 코드 포인트 반복 할.

위키 백과의 UTF-16


8

문자 뒤의 코드에 관한 것입니다. 일부는 2 바이트 (UTF-16)로 코딩 Array.from되며 두 문자로 해석됩니다 . 문자 목록을 확인해야합니다.

http://www.fileformat.info/info/charset/UTF-8/list.htm

http://www.fileformat.info/info/charset/UTF-16/list.htm

function displayHexUnicode(s) {
  console.log(s.split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(4,"0"),""));
}

displayHexUnicode('षि');

console.log(Array.from('षि').forEach(x => displayHexUnicode(x)));


function displayHexUnicode(s) {
  console.log(s.split("").reduce((hex,c)=>hex+=c.charCodeAt(0).toString(16).padStart(4,"0"),""));
}

displayHexUnicode('👍');

console.log(Array.from('👍').forEach(x => displayHexUnicode(x)));


16 진 코드를 표시하는 기능 :

자바 스크립트 : 유니 코드 문자열을 16 진수로

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.