검색 결과 누락 해결: NFKC와 토큰 검색

이 글의 목차 7개 항목
  • 분야: FE
  • 기술 스택: React · TypeScript(TSX)
  • 관련 기술: Unicode NFKC · 문자열 정규화 · 다중 토큰 AND 검색

문제와 원인

기존 검색은 입력 끝의 공백과 대소문자만 정리했다. 데이터 베이스는 대상 데이터베이스·SQL과 내부 공백이 달랐고, 전각 sql은 반각 sql과 달랐다. 별칭 정처기도 정식 과정명 정보처리에 포함되지 않아 검색에서 빠졌다.

수정 전 코드

matchesSearchQuery()

function matchesSearchQuery(query: string, ...values: string[]) {
  const normalized = query.trim().toLocaleLowerCase("ko-KR");
  return !normalized || values.some((value) => (
    value.toLocaleLowerCase("ko-KR").includes(normalized)
  ));
}

수정 후 코드

SW 과정 선택에 공유 함수 matchesLearningSearch를 적용했다. 입력과 대상 모두 NFKC·소문자·별칭 치환을 거친다. 대상은 공백을 제거하고, 검색어는 토큰으로 나눠 모두 포함될 때 일치시킨다. 빈 검색어는 전체 항목을 통과시킨다.

matchesSearchQuery 연결

import { matchesLearningSearch as matchesSearchQuery } from "@shared/study/learning-search";

normalizedLearningSearchTokens() · matchesLearningSearch()

export function normalizedLearningSearchTokens(query: string) {
  return query.normalize("NFKC").toLocaleLowerCase("ko-KR")
    .replace(/정처기/gu, "정보처리")
    .trim()
    .split(/\s+/u)
    .filter(Boolean);
}

export function matchesLearningSearch(query: string, ...values: unknown[]) {
  const text = values
    .map(value => String(value ?? ""))
    .join(" ")
    .normalize("NFKC")
    .toLocaleLowerCase("ko-KR")
    .replace(/정처기/gu, "정보처리")
    .replace(/\s+/gu, "");

  return normalizedLearningSearchTokens(query)
    .every(token => text.includes(token));
}

검증 결과

로컬 함수 비교 6조건에서 같은 대상 문자열에 기존 함수·공유 함수를 적용했다. 누락됐던 4조건은 0/4 → 4/4, 전체 기대값 일치는 2/6 → 6/6으로 바뀌었다.

입력 조건기대 결과수정 전수정 후
띄어쓴 단어일치불일치일치
과정명 내부 띄어쓰기일치불일치일치
전각 영문일치불일치일치
별칭일치불일치일치
무관한 검색불일치불일치불일치
빈 검색일치일치일치

matchesLearningSearch("데이터 베이스", "데이터베이스·SQL")은 true, 같은 입력과 운영체제의 비교는 false다. sql은 NFKC 변환 뒤 sql로 검색된다.

같은 검색어·대상 문자열 여섯 쌍을 로컬 Node의 원본 전후 함수에 각 1회 다시 전달했다. 띄어쓰기·전각·별칭 네 입력이 모두 일치했고 무관한 문자열과 빈 검색어의 판정은 같았다.

검색 정규화 6조건의 기대값 일치 2개에서 6개로 변경원본 보기 (새 창)

검색 정규화 6조건의 기대값 일치 2개에서 6개로 변경

100%원본 보기 (새 창)

확대한 이미지는 상하좌우로 이동할 수 있습니다. 키보드는 이미지 영역에 초점을 두고 방향키를 사용하세요. Esc로 닫습니다.