split() 메서드의 문제점


자바스크립트에서 문자열을 분리할 때 일반적으로 split() 메서드를 사용한다. 하지만 아래처럼 구분자는 결과 배열에서 제외되고 불필요한 공백이 추가된다. 즉, language-sensitive 하지 않는 단점이 있다. language-sensitive는 문맥에 맞는 표현과 용어 사용을 의미한다. 한국어로는 언어 감수성이라고 부른다.

'Hello! How are you?'.split(/[.!?]/);
// ['Hello', ' How are you', '']

<aside> 💡 정규식 관련 참고

Intl 자바스크립트 API를 활용하면 위 같은 문제를 말끔하게 해결할 수 있다.

Intl.Segmenter


Intl.Segmenter 메서드를 사용하면 문자열을 의미있는 단위로 분리할 수 있다. locale granularity를 정의한 후 segment 메서드 파라미터에 분리하고 싶은 문자열을 추가하는 방식으로 사용한다.

<aside> 💡 granularity 옵션(颗粒选项) 종류

segment 메서드는 정의한 locale granularity 옵션에 따라 문자열의 세그먼트를 나타내는 Segments 인스턴스를 반환한다. Segments 인스턴스는 이터러블이다. 따라서 전개연산자 Array.from for of 문 등에서 사용할 수 있다.

const segmenterKo = new Intl.Segmenter('ko', { granularity: 'word' });
const segmentsKo = segmenterKo.segment('안녕하세요, 반갑습니다');

console.log([...segmentsKo])
/*
{ segment: '안녕하세요', index: 0, input: '안녕하세요, 반갑습니다', isWordLike: true }
{ segment: ',', index: 5, input: '안녕하세요, 반갑습니다', isWordLike: false }
{ segment: ' ', index: 6, input: '안녕하세요, 반갑습니다', isWordLike: false }
{ segment: '반갑습니다', index: 7, input: '안녕하세요, 반갑습니다', isWordLike: true }
*/
const segmenterKo = new Intl.Segmenter('ko', { granularity: 'sentence' });
const segmentsKo = segmenterKo.segment('안녕하세요, 반갑습니다');

console.log([...segmentsKo])
/*
{ "segment": "안녕하세요, 반갑습니다", "index": 0, "input": "안녕하세요, 반갑습니다" }
*/
const segmenterKo = new Intl.Segmenter('ko', { granularity: 'grapheme' });
const segmentsKo = segmenterKo.segment('안녕하세요, 반갑습니다');

console.log([...segmentsKo])
/*
{ "segment": "안", "index": 0, "input": "안녕하세요, 반갑습니다" }
{ "segment": "녕", "index": 1, "input": "안녕하세요, 반갑습니다" }
{ "segment": "하", "index": 2, "input": "안녕하세요, 반갑습니다" }
...
*/

isWordLike 프로퍼티


<aside> 💡 isWordLike 프로퍼티는 word 기준으로 문자열을 분리했을 때만 포함된다

</aside>

만약 word를 기준으로 문자열을 분리했다면, 모든 세그먼트는 단어뿐만 아니라 공백(whitespace), 구두점(punctuation) 및 줄바꿈(line breaks)을 포함할 수 있다. 여기서 단어만 추출하고 싶으면 isWordLike 프로퍼티를 이용해 필터링 하면 된다. isWordLike는 세그먼트가 단어와 유사한지 여부를 나타내는 불리언 값이다.

const segmenterKo = new Intl.Segmenter('ko', { granularity: 'word' });
const segmentsKo = segmenterKo.segment('안녕하세요, 반갑습니다');

console.log([...segmentsKo].filter(s => s.isWordLike));
/*
{ "segment": "안녕하세요", "index": 0, "input": "안녕하세요, 반갑습니다", "isWordLike": true }
{ "segment": "반갑습니다", "index": 7, "input": "안녕하세요, 반갑습니다", "isWordLike": true }
*/