[JS] 문자열간의 비교

MJ·2022년 9월 21일
0

Java Script

목록 보기
42/57
post-thumbnail

문자열간의 비교

비교 연산자를 사용해서 문자열간의 크기를 비교할 수 있습니다. 알파벳 순서에 따라서
크기가 결정되고, 소문자는 대문자보다 크며 za보다 큽니다.

다만 문자열간을 비교할 때, 규칙에서 벗어나는 예외 상황이 있습니다.

alert( 'a' > 'Z' );	// true, 소문자는 대문자보다 크다.
alert( 'Österreich' > 'Zealand' );	// true
// true, 발음 구별 기호가 붙은 문자는 알파벳 순서 기준을 따르지 않음
// 발음 구별 기호가 아닌 일반 O 였다면, false가 나왓을 것

문자열과 인코딩

모든 문자열은 UTF-16을 사용해 인코딩 되는데, UTF-16에선 모든 글자가 숫자 형식의
코드와 매칭된다. 코드로 글자를 얻거나 글자에서 연관 코드를 알아낼 수 있는 메서드들은
다음과 같다.


str.codePointAt(position)

str 문자열에서 position에 위치한 문자열의 코드를 반환합니다.
문자열에 대한 숫자 값을 반환.

alert( 'z'.codePointAt(0) );	// 122, 'z' 의 코드 값을 반환
alert( 'aZ'.codePointAt(1) );	// 90, 'aZ'에서 'Z'의 코드 값을 반환


/* */
❗ 인수가 없으면, 문자열의 [0]번째에 해당하는 코드 값을 반환합니다.

String.fromCodePoint(code)

인수로 받은 숫자(코드 값)와 매핑된 문자열로 반환합니다.

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간의 문자열 비교를 할 수 있습니다. 비교의 반환 값은 정수입니다.

  • strstr2보다 작으면 음수를 반환
  • strstr2보다 크면 양수를 반환
  • strstr2과 같다면 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.fromCodePointstr.codePointAt
서로게이트 쌍을 처리할 수 있는 메서드입니다.

서로게이트 쌍은 두 글자로 취급하기에 기호를 가져오는게 까다롭습니다.

alert( '𝒳'[0] ); // 이상한 기호가 출력됨
alert( '𝒳'[1] ); // 서로게이트 쌍의 일부가 출력됨
// '𝒳' 기호는 2개의 글자로 합쳐 있는데, 1개씩 출력하니 이상한 기호가 출력되는 것

서로게이트 쌍을 구성하는 글자들은 붙어있을 때만 의미가 있습니다. 그래서 위 예시에는
의미없는 기호가 출력됩니다. 서로게이트 쌍의 첫 번째 글자는 0xd800 ~ 0xdbff 사이에
코드가 존재해야 합니다. 서로게이트 쌍의 두 번쨰 글자는 0xdc00 ~ 0xdfff 사이에 존재
해야 합니다.

0xd800 ~ 0xdbff0xdc00 ~ 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]

부분 문자열을 추출하려면 slicesubstring을 사용하자.


문자열을 대-소문자로 변경하는데 사용하는 두 가지 메서드가 있다.
소문자 변경 시 toLowerCase() | 대문자 변경 시 toUpperCase()


indexOf를 사용하면 부분 문자열의 위치를 얻을 수 있다.
부분 문자열이 존재하는지에 대한 유무만 확인하고 싶다면, inclues/startsWith/endsWith


특정 언어에 적합한 비교 기준을 사용해 문자열을 비교하려면 localeCompare 메서드를 사용
이 메서드를 사용하지 않으면, 글자 코드를 기준으로 문자열이 비교 된다.

profile
프론트엔드 개발자가 되기 위한 학습 과정을 정리하는 블로그

0개의 댓글