아스트랄 평면 코드 포인트 또는 관련 문제에 대한 기존 답변에서 언급을 보지 못했습니다. 국제화 . “대문자”는 특정 스크립트를 사용하는 모든 언어에서 동일한 것을 의미하지는 않습니다.
처음에는 아스트랄 평면 코드 포인트와 관련된 문제를 해결하는 답변을 보지 못했습니다. 이 하나 , 그러나 묻혀 약간의 (이 하나가 될 것 같은 것 같아요!)
제안 된 기능의 대부분은 다음과 같습니다.
function capitalizeFirstLetter(str) {
return str[0].toUpperCase() + str.slice(1);
}
그러나 일부 사례 문자는 BMP (기본 다국어 평면, 코드 포인트 U + 0 ~ U + FFFF)를 벗어납니다. 예를 들어 다음 Deseret 텍스트를 보자.
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉"); // "𐐶𐐲𐑌𐐼𐐲𐑉"
문자열의 배열 색인 속성이 "문자"또는 코드 포인트 *에 액세스하지 않기 때문에 여기서 첫 번째 문자는 대문자로 표시되지 않습니다. UTF-16 코드 단위에 액세스합니다. 슬라이스 할 때도 마찬가지입니다. 인덱스 값은 코드 단위를 가리 킵니다.
UTF-16 코드 단위는 U + 0 ~ U + D7FF 및 U + E000 ~ U + FFFF 포함의 두 범위 내에서 USV 코드 포인트가있는 1 : 1입니다. 대부분의 경우 문자는이 두 범위에 속하지만 전부는 아닙니다.
ES2015부터는 이것을 다루는 것이 약간 쉬워졌습니다. String.prototype[@@iterator]
코드 포인트 **에 해당하는 문자열을 생성합니다. 예를 들어 다음과 같이 할 수 있습니다.
function capitalizeFirstLetter([ first, ...rest ]) {
return [ first.toUpperCase(), ...rest ].join('');
}
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
더 긴 문자열의 경우, 아마도 그렇게 효율적이지 않을 것입니다. *** 우리는 실제로 나머지를 반복 할 필요가 없습니다. 우리는 String.prototype.codePointAt
첫 번째 (가능한) 편지를 얻는 데 사용할 수 있지만 여전히 슬라이스 시작 위치를 결정해야합니다. 나머지를 반복하지 않는 한 가지 방법은 첫 번째 코드 포인트가 BMP 외부에 있는지 테스트하는 것입니다. 그렇지 않으면 슬라이스는 1에서 시작하고, 그렇지 않으면 슬라이스는 2에서 시작합니다.
function capitalizeFirstLetter(str) {
const firstCP = str.codePointAt(0);
const index = firstCP > 0xFFFF ? 2 : 1;
return String.fromCodePoint(firstCP).toUpperCase() + str.slice(index);
}
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
대신에 비트 수학을 사용할 수 있습니다 > 0xFFFF
있지만이 방법을 이해하는 것이 더 쉬울 수도 있고 같은 것을 얻을 수도 있습니다.
필요한 경우 해당 논리를 조금 더 발전시켜 ES5 이하에서이 작업을 수행 할 수도 있습니다. ES5에는 코드 포인트 작업을위한 내장 메소드가 없으므로 첫 번째 코드 단위가 대리 ****인지 수동으로 테스트해야합니다.
function capitalizeFirstLetter(str) {
var firstCodeUnit = str[0];
if (firstCodeUnit < '\uD800' || firstCodeUnit > '\uDFFF') {
return str[0].toUpperCase() + str.slice(1);
}
return str.slice(0, 2).toUpperCase() + str.slice(2);
}
capitalizeFirstLetter("𐐶𐐲𐑌𐐼𐐲𐑉") // "𐐎𐐲𐑌𐐼𐐲𐑉"
처음에는 국제화 고려 사항도 언급했습니다. 이들 중 일부는 무엇에 대한 지식뿐만 아니라 지식이 필요하기 때문에 설명하기가 매우 어렵습니다 언어를 사용하고, 그러나 또한 언어로 단어의 구체적인 지식을 필요로 할 수있다. 예를 들어, 아일랜드어 "mb"는 단어의 시작 부분에서 "mB"로 대문자로 표시됩니다. 또 다른 예인 독일어 eszett는 단어 (afaik)를 시작하지 않지만 여전히 문제를 설명하는 데 도움이됩니다. 소문자 eszett ( "ß")는 "SS"로 대문자를 사용하지만 "SS"는 "ß"또는 "ss"로 소문자를 지정할 수 있습니다. 어떤 언어가 올바른지 알기 위해서는 독일어에 대한 대역 외 지식이 필요합니다!
이러한 종류의 문제 중 가장 유명한 예는 아마도 터키어입니다. 터키어 라틴어에서 i의 대문자는 İ이며 소문자는 ı입니다. 두 개의 다른 문자입니다. 다행히도 우리는 이것을 설명 할 방법이 있습니다.
function capitalizeFirstLetter([ first, ...rest ], locale) {
return [ first.toLocaleUpperCase(locale), ...rest ].join('');
}
capitalizeFirstLetter("italy", "en") // "Italy"
capitalizeFirstLetter("italya", "tr") // "İtalya"
브라우저에서 사용자가 가장 선호하는 언어 태그는로 표시되고 navigator.language
선호하는 순서대로 목록 이 표시되며 다국어 문서에서 navigator.languages
주어진 DOM 요소의 언어를 (일반적으로) 얻을 수 있습니다 Object(element.closest('[lang]')).lang || YOUR_DEFAULT_HERE
.
ES2018에 도입 된 RegExp에서 유니 코드 속성 문자 클래스를 지원하는 에이전트에서 관심있는 문자를 직접 표현하여 정리할 수 있습니다.
function capitalizeFirstLetter(str, locale=navigator.language) {
return str.replace(/^\p{CWU}/u, char => char.toLocaleUpperCase(locale));
}
이것은 상당히 좋은 정확도로 문자열에서 여러 단어를 대문자로 처리하도록 약간 조정될 수 있습니다. CWU
또는 Changes_When_Uppercased 문자 속성은 물론, 변화 대문자로 모든 코드 포인트와 일치합니다. 예를 들어 Dutch ij 와 같은 제목이있는 digraph 문자를 사용하여이 작업을 시도 할 수 있습니다 .
capitalizeFirstLetter('ijsselmeer'); // "IJsselmeer"
작성 당시 (2020 년 2 월) Firefox / Spidermonkey는 지난 2 년 동안 소개 된 RegExp 기능을 아직 구현하지 않았습니다 *****. Kangax compat 테이블 에서이 기능의 현재 상태를 확인할 수 있습니다 . Babel은 해당 패턴이없는 동등한 패턴에 대한 속성 참조가있는 RegExp 리터럴을 컴파일 할 수 있지만 결과 코드는 엄청날 수 있습니다.
아마이 질문을하는 사람들은 Deseret 대문자 또는 국제화에 관심이 없을 것입니다. 그러나 현재 문제가되지 않더라도 결국에는 문제가 발생할 가능성이 높기 때문에 이러한 문제를 알고있는 것이 좋습니다. 그것들은“가장자리”가 아니고 오히려 정의가 명확한 경우 가 아닙니다 . 대부분의 사람들이 터키어를 사용하는 나라가 있습니다. 어쨌든 코드 단위가있는 코드 단위를 묶는 것은 상당히 일반적인 버그의 원인입니다 (특히 이모티콘과 관련하여). 문자열과 언어는 매우 복잡합니다!
* UTF-16 / UCS2의 코드 단위는 또한 U + D800이 기술적으로 코드 포인트라는 점에서 유니 코드 코드 포인트입니다. 그러나 이것이 "의미"한 것은 아닙니다. 흐린. 그러나 대리자가 확실히 아닌 것은 USV (유니 코드 스칼라 값)입니다.
** 대리 코드 단위가 "분리 된"(즉, 논리 쌍의 일부가 아닌) 경우에도 여전히 대리자를 얻을 수 있습니다.
*** 아마도. 나는 그것을 테스트하지 않았습니다. 대문자 사용이 의미있는 병목 현상이 아니라면 땀을 흘리지 않을 것입니다. 가장 명확하고 읽기 쉬운 항목을 선택하십시오.
**** 이러한 함수는 첫 번째 단위가 분리 된 대리 일 가능성이 있기 때문에 첫 번째 코드 대신 첫 번째 코드 단위와 두 번째 코드 단위를 모두 테스트하려고 할 수 있습니다. 예를 들어 입력 "\ uD800x"는 X를 그대로 대문자로 표시하므로 예상되거나 예상되지 않을 수 있습니다.
***** 진행 상황을 더 직접적으로 따르고 싶다면 Bugzilla 문제 가 있습니다.