문제 상황
JavaScript 개발을 하다 보면 두 개의 문자열 배열에서 특정 단어가 몇 번 등장하는지 정확하게 집계해야 하는 경우가 자주 있습니다. 예를 들어 다음과 같이 하나의 배열에는 이름(단어)들이, 다른 배열에는 문장들이 담겨 있다고 가정해 보겠습니다.
const names = ["jhon", "parker"]; const sentences = [ "hello jhon", "hello parker and parker", "jhonny jhonny yes parker" ];
여기서 요구되는 것은 두 개의 문자열 배열을 인자로 받아, 첫 번째 배열(names)에 있는 각 단어가 두 번째 배열(sentences) 전체에서 몇 번 나타나는지를 계산하여 객체 형태로 반환하는 함수를 작성하는 것입니다.
위 예제 데이터의 경우, 최종 출력 결과는 다음과 같은 형태가 됩니다.
const output = {
"jhon": 1,
"parker": 3
};parker가 3으로 카운트된 이유는 두 번째 문장에서 한 번, 세 번째 문장에서 한 번, 그리고 첫 번째와 두 번째 문장에서 각각 한 번씩 등장하기 때문입니다. 반면 jhonny는 jhon과 철자가 비슷하지만 별개의 단어이므로 jhon의 카운트에는 포함되지 않아야 합니다.
해결 방법: 정규표현식 활용
이 문제를 해결하는 가장 깔끔한 방법은 정규표현식(RegExp)을 사용하는 것입니다. 핵심 포인트는 다음과 같습니다.
- 단어 경계(\b): \b 메타 문자를 사용하면 부분 일치가 아닌 완전한 단어 단위로만 매칭됩니다. 덕분에 'jhon'이 'jhonny' 안에서 잘못 매칭되는 것을 방지할 수 있습니다.
- OR 연산자(|): 여러 이름을 하나의 패턴으로 결합해 한 번의 검색으로 모든 단어를 찾습니다.
- g 플래그: 문장 내에서 일치하는 모든 항목을 찾도록 합니다.
- i 플래그: 대소문자를 구분하지 않고 매칭합니다.
구현 코드
const names = ["jhon", "parker"];
const sentences = [
"hello jhon",
"hello parker and parker",
"jhonny jhonny yes parker"
];
const countAppearances = (names = [], sentences = []) => {
// 각 이름을 단어 경계가 적용된 정규표현식 패턴으로 변환
const pattern = new RegExp(
names.map(name => `\\b${name}\\b`).join('|'),
'gi'
);
const res = {};
for (const sentence of sentences) {
for (const match of (sentence.match(pattern) || [])) {
res[match] = (res[match] || 0) + 1;
}
}
return res;
};
console.log(countAppearances(names, sentences));
코드 동작 원리 살펴보기
names.map(name => `\\b${name}\\b`)는 각 이름을\\bjhon\\b|\\bparker\\b형태의 패턴으로 만듭니다.'gi'플래그로 대소문자 구분 없이 모든 일치 항목을 검색합니다.- 각 문장마다
sentence.match(pattern)으로 일치한 단어 목록을 가져오고, 일치 항목이 없으면 빈 배열(|| [])을 사용해 오류를 방지합니다. res[match] = (res[match] || 0) + 1코드는 해당 단어가 처음 등장하면 0으로 초기화한 뒤 1을 더하는 방식으로 카운트를 누적합니다.
실행 결과
콘솔에 출력되는 결과는 다음과 같습니다.
{ jhon: 1, parker: 3 }
추가 고려 사항
만약 대소문자를 구분해야 하는 경우라면 정규표현식 생성 시 'gi' 플래그 대신 'g'만 사용하면 됩니다. 또한 결과 객체의 키가 원본 names 배열의 순서나 대소문자를 유지해야 한다면, 매칭된 값을 소문자화한 뒤 원래 키로 다시 매핑하는 후처리 과정을 추가할 수 있습니다. 이처럼 정규표현식과 단어 경계를 활용하면 유사한 단어(jhon vs jhonny)까지 정확하게 구분하는 신뢰성 높은 단어 출현 횟수 집계 기능을 손쉽게 구현할 수 있습니다.