비교 연산자를 사용해서 문자열간의 크기를 비교할 수 있습니다. 알파벳 순서에 따라서
크기가 결정되고, 소문자는 대문자보다 크며 z
는 a
보다 큽니다.
다만 문자열간을 비교할 때, 규칙에서 벗어나는 예외 상황이 있습니다.
alert( 'a' > 'Z' ); // true, 소문자는 대문자보다 크다.
alert( 'Österreich' > 'Zealand' ); // true
// true, 발음 구별 기호가 붙은 문자는 알파벳 순서 기준을 따르지 않음
// 발음 구별 기호가 아닌 일반 O 였다면, false가 나왓을 것
모든 문자열은 UTF-16
을 사용해 인코딩 되는데, UTF-16
에선 모든 글자가 숫자 형식의
코드와 매칭된다. 코드로 글자를 얻거나 글자에서 연관 코드를 알아낼 수 있는 메서드들은
다음과 같다.
str
문자열에서 position
에 위치한 문자열의 코드를 반환합니다.
문자열에 대한 숫자 값을 반환.
alert( 'z'.codePointAt(0) ); // 122, 'z' 의 코드 값을 반환
alert( 'aZ'.codePointAt(1) ); // 90, 'aZ'에서 'Z'의 코드 값을 반환
/* */
❗ 인수가 없으면, 문자열의 [0]번째에 해당하는 코드 값을 반환합니다.
인수로 받은 숫자(코드 값)와 매핑된 문자열로 반환합니다.
alert( String.fromCodePoint(90) ); // 'Z', 숫자 90과 매핑하는 문자열은 'Z'입니다.
alert( '\u005a' );
// 'Z' , \u 유니코드방식을 사용해서 16진수에 해당하는 문자열을 출력
// 16진수 5a는 10진수로 90
해당 메서드와 반복문을 사용해서 코드 값(숫자) 사이에 어떤 문자들이 있는 지 확인 해봅시다.
let str=''; // 문자열 간의 병합을 위해서 빈 문자열 생성
for (let i = 65; i <= 220; i++) {
str += String.fromCodePoint(i); // 65 ~ 220 사이에 있는 문자열들이 병합된다.
}
alert( str );
// ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
// ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜ
🔔 문자에 매핑된 숫자 값
문자에 매핑된 숫자값을 보고, 소문자가 대문자보다 크고Ö
기호가 대문자 'Z' 보다
크다는 것을 확인 할 수 있습니다.
다른 환경과 문자열 비교는 사용하는 문자 체계가 다를 수 있기에 문자열 비교가 간단치 않다.
문자열을 비교하려면, 먼저 페이지가 어떤 언어를 사용하는지 알아야 합니다.
대부분의 모던 브라우저들은 국제화 관련 표준인 ECMA-402를 지원합니다.
(IE10은 지원하지 않기에 lntl.js 라이브러리를 사용해야 합니다.)
ECMA-402엔 언어가 다를 때 적용할 수 있는 문자열 비교 규칙과 이를 준수하는 메서드가
정의되어 있습니다.
str.localeCompare(str2)
를 호출하면 ECMA-402에서 정의한 규칙에 따라 str
과
str2
간의 문자열 비교를 할 수 있습니다. 비교의 반환 값은 정수입니다.
str
이 str2
보다 작으면 음수
를 반환str
이 str2
보다 크면 양수
를 반환str
이 str2
과 같다면 0
을 반환alert( 'Österreich'.localeCompare('Zealand') ); // -1
// 음수와 양수 값은 환경에 따라서 2나 -2일수도 있습니다.
// 값을 보지 말고, 부호를 확인 하자
// 발음 구별 기호를 구분하지 않았기에, Ö를 O로 인식하기에 더 작다고 표현됩니다.
localCompare()
메서드는 선택적인 인수 두 개를 더 전달할 수 있습니다.
기준이 되는 언어를 지정해주는 인수와, 대-소문자를 구분할 것인지, a
와 á
를 다르게 취급
할 것인지를 설정 해주는 인수가 있습니다. 자세한 정보는 이곳에서 확인 바랍니다.
자주 사용되는 글자들은 모두 2바이트 코드를 가지고 있습니다. 유럽권 언어에서 사용되는 글자,
숫자, 상형문자 대다수는 2바이트를 표현 체계를 사용합니다.
2바이트는 2의 16승(65,536)개의 조합밖에 만들 수 없어 현존하는 모든 기호를 표현하기에는
부족함이 있습니다. 이를 극복하기 위해서 사용 빈도가 낮은 기호는 '서로게이트 쌍'이라 불리
는 2바이트 글자들의 쌍을 이용해 인코딩 합니다. (surrogate pair)
서로게이트 쌍을 사용해 인코딩한 기호의 길이는 2
입니다.
alert( '𝒳'.length ); // 2, 수학에서 쓰이는 대문자 X(그리스 문자 카이)
alert( '😂'.length ); // 2, 웃으면서 눈물 흘리는 얼굴을 나타내는 이모티콘
alert( '𩷶'.length ); // 2, 사용 빈도가 낮은 중국어(상형문자)
JS
가 만들어진 당시에는 서로게이트 쌍이라는 개념이 없었습니다.
따라서 JS
는 서로게이트 쌍으로 표현한 기호를 제대로 처리하지 못합니다. 위 예시에서 기호
는 1개이나 문자열을 2개로 처리 하는 이유가 이에 해당합니다.
새로 명세서에 추가된 메서드 String.fromCodePoint
와 str.codePointAt
가
서로게이트 쌍을 처리할 수 있는 메서드입니다.
서로게이트 쌍은 두 글자로 취급하기에 기호를 가져오는게 까다롭습니다.
alert( '𝒳'[0] ); // 이상한 기호가 출력됨
alert( '𝒳'[1] ); // 서로게이트 쌍의 일부가 출력됨
// '𝒳' 기호는 2개의 글자로 합쳐 있는데, 1개씩 출력하니 이상한 기호가 출력되는 것
서로게이트 쌍을 구성하는 글자들은 붙어있을 때만 의미가 있습니다. 그래서 위 예시에는
의미없는 기호가 출력됩니다. 서로게이트 쌍의 첫 번째 글자는 0xd800 ~ 0xdbff
사이에
코드가 존재해야 합니다. 서로게이트 쌍의 두 번쨰 글자는 0xdc00 ~ 0xdfff
사이에 존재
해야 합니다.
0xd800 ~ 0xdbff
와 0xdc00 ~ 0xdfff
는 표준에서 서로게이트 쌍을 위해 일부로 비워
둔 코드 입니다.
alert( '𝒳'.charCodeAt(0).toString(16) );
// d835, 𝒳 기호에 첫 번째 값을 16진수로 표현, 0xd800과 0xdbff 사이의 코드
alert( '𝒳'.charCodeAt(1).toString(16) );
// dcb3, 𝒳 기호에 두 번째 값을 16진수로 표현, 0xdc00과 0xdfff 사이의 코드
/* */
charCodeAt 메서드는 서로게이트 쌍을 처리하지 못하기에 서로게이트 쌍을 구성하는
부분에 대한 코드를 반환합니다.
str.codePointAt()
메서드로 str
에 해당하는 서로게이트 쌍 문자를 코드 값으로 반환
할 수 있습니다. 반환 된 코드 값에 해당하는 문자로 다시 변환하려면
String.fromCodePoint()
메서드를 사용할 수 있습니다.
alert( '𝒳'.codePointAt() ); // 119987, 𝒳 문자에 대한 서로게이트 쌍 값
alert( String.fromCodePoint(119987) ) ; // 𝒳, 119987 값에 해당하는 문자 출력
여러 언어에서 베이스가 되는 글자 위나 아래에 발음 구별 기호를 붙여 글자를 만듭니다
베이스 글자a
를 , àáâäãåā
로 만드는 것 처럼 말입니다. 이런 합성 글자 대부분은 UTF-16
테이블에서 독자적인 코드를 갖습니다. 하지만 모든 합성 글자에 코드가 부여되진 않습니다.
조합 가능한 글자의 수가 많기 때문입니다.
임의의 조합을 지원하기 위해 UTF-16
은 몇 개의 유니코드 문자를 남겨놨습니다.
베이스 글자 뒤에 유니코드 문자를 붙여서 베이스 글자를 꾸밀 수 있도록 말입니다.
alert( 'S\u0307' ); // Ṡ, 베이스 글자 S 뒤에 유니코드 문자(\u0307)를 붙여 Ṡ 기호를 만듬
alert( 'S\u0307\u0323' ); // Ṩ, 하나의 베이스 글자에 여러 개의 발음 구별 기호를 붙일 수 있음
하나의 베이스 글자에 여러 개의 유니코드 문자를 사용해서 발음 기호를 다양하게 붙일 수
있습니다. 하지만 단점으로는 유니코드의 조합이 다른 경우엔 같은 발음 구별 기호도 같지
않게 표현 됩니다.
let s1 = 'S\u0307\u0323'; // Ṩ
let s2 = 'S\u0323\u0307'; // Ṩ
alert( s1 == s2 ); // false, 눈으로 보기엔 같은 글자지만 조합이 다르기에 false
이런 문제를 해결하기 위해서 유니코드 정규화라고 불리는 알고리즘을 사용해 각 문자열을
동일한 형태로 정규화 합니다. (unicode normalization)
유니코드 정규화 알고리즘은 str.normalize()프로퍼티에 구현되어 있습니다.
alert( 'S\u0307\u0323'.normalize() == 'S\u0323\u0307' ); // true
normalize()
프로퍼티를 사용하면, 여러 개의 문자가 하나의 문자로 합쳐집니다.
S\u0307\u0323
같은 경우에는 \u1e68
로 합쳐집니다.
alert( "S\u0307\u0323".normalize().length ); // 1
alert( "S\u0307\u0323".normalize() == "\u1e68" ); // true
⚠️ 정규화 방식 주의점
정규화 방식을 사용해도 모든 기호가 동동하진 않습니다.
Ṩ
같은 기호는UTF-16
을 개발한 사람들이 충분히 나타날 수 있는 사례라고 생각하고
UTF-16
테이블에 코드를 부여한 것이므로, 예상치 못한 기호의 조합을 사용하면 동등
하지 않다고 나타날 수 있습니다.
JS
에는 세 종류의 따옴표가 있고, 이 중에서 백틱인 역 따옴표는 문자열을 여러 줄에 걸쳐
표현할 수 있게 하며, 문자열 도중 ${ }에 표현식을 삽입할 수 있다.
JS
에선 UTF-16
을 사용해 문자열을 인코딩한다.
\n
같은 특수문자를 사용할 수 있고, \u...
를 사용하면 해당 문자의 유니코드를 사용해서
글자로 만들 수 있다.
문자열 내에서 글자 하나를 얻으려면 []
를 사용하면 된다.
let str = string
에서 's'만 얻고 싶다면 str[0]
부분 문자열을 추출하려면 slice
나 substring
을 사용하자.
문자열을 대-소문자로 변경하는데 사용하는 두 가지 메서드가 있다.
소문자 변경 시 toLowerCase()
| 대문자 변경 시 toUpperCase()
indexOf
를 사용하면 부분 문자열의 위치를 얻을 수 있다.
부분 문자열이 존재하는지에 대한 유무만 확인하고 싶다면, inclues/startsWith/endsWith
특정 언어에 적합한 비교 기준을 사용해 문자열을 비교하려면 localeCompare
메서드를 사용
이 메서드를 사용하지 않으면, 글자 코드를 기준으로 문자열이 비교 된다.