공백을 지웠는데도 검색이 안 될 때: NBSP와 숨은 문자 확인

데이터를 정리할 때 분명히 양쪽 끝 공백을 제거하고 동일한 단어로 검색했는데도 일치하는 결과가 없거나, 프로그래밍 언어의 동등 비교(==)에서 False가 반환되는 상황을 자주 겪습니다. 눈으로 볼 때는 평범한 빈칸이거나 심지어 빈칸조차 없어 보이는 위치에 일반 공백이 아닌 다른 유니코드 문자가 숨어 있는 경우가 많기 때문입니다.

단순히 모든 공백성 문자를 한꺼번에 지우거나 치환해 버리면 데이터의 원래 의미나 레이아웃이 훼손될 수 있습니다. 과거 중복 줄 제거: 공백과 한글 정규화 차이에서 다룬 것처럼 겉보기 형태와 실제 바이트 구성은 다를 수 있으므로, 먼저 각 문자의 정확한 정체를 확인하는 진단 과정이 필요합니다.

눈에 보이지 않지만 서로 다른 세 가지 공백

키보드의 스페이스바로 입력하는 일반 공백(ASCII 32, U+0020) 외에도 텍스트에는 다양한 공백 또는 제어 문자가 섞여 들어올 수 있습니다. 대표적으로 웹 페이지를 긁어오거나 서식 있는 문서에서 복사할 때 유입되는 줄 바꿈 방지 공백(NO-BREAK SPACE, U+00A0)과, 화면에는 아무런 너비도 차지하지 않으면서 단어 사이에 숨어 있는 폭 없는 공백(ZERO WIDTH SPACE, U+200B)이 있습니다.

이 문자들은 화면에 표시될 때 일반 빈칸과 구별하기 어렵거나 아예 보이지 않습니다. 따라서 텍스트 에디터나 브라우저 화면만 보고 판단하면 같은 문자열인데 왜 검색되지 않는지 원인을 파악하기 어렵습니다.

코드 포인트와 유니코드 이름 확인하기

문자열의 내부 구성을 확인하려면 각 글자를 분리하여 16진수 코드 포인트와 공식 유니코드 이름을 조회해야 합니다. 파이썬에서는 내장 함수 ord()로 코드 번호를 얻고, 표준 라이브러리인 Python — unicodedata.name과 문자 정보 모듈의 unicodedata.name()을 통해 해당 글자의 공식 이름을 확인할 수 있습니다.

import unicodedata

def inspect_chars(text):
    for ch in text:
        code = f"U+{ord(ch):04X}"
        name = unicodedata.name(ch, "UNKNOWN")
        print(f"{ch!r} -> {code} : {name}")

이 함수에 문제를 일으키는 문자열을 전달하면, 일반 공백인지, NBSP인지, 아니면 폭 없는 공백인지 명확하게 구분할 수 있습니다.

재현 입력과 확인된 유니코드 분석

동일하게 A와 B 사이에 공백이 들어간 것처럼 보이거나 붙어 있는 것처럼 보이는 세 가지 문자열을 비교한 결과입니다.

[
  {
    "text": "'A B'",
    "codes": [
      "U+0041",
      "U+0020",
      "U+0042"
    ],
    "names": [
      "LATIN CAPITAL LETTER A",
      "SPACE",
      "LATIN CAPITAL LETTER B"
    ]
  },
  {
    "text": "'A\\xa0B'",
    "codes": [
      "U+0041",
      "U+00A0",
      "U+0042"
    ],
    "names": [
      "LATIN CAPITAL LETTER A",
      "NO-BREAK SPACE",
      "LATIN CAPITAL LETTER B"
    ]
  },
  {
    "text": "'A\\u200bB'",
    "codes": [
      "U+0041",
      "U+200B",
      "U+0042"
    ],
    "names": [
      "LATIN CAPITAL LETTER A",
      "ZERO WIDTH SPACE",
      "LATIN CAPITAL LETTER B"
    ]
  }
]

첫 번째 문자열은 일반 공백(SPACE)이 사용되었으나, 두 번째 문자열은 NO-BREAK SPACE(U+00A0)가, 세 번째 문자열은 눈에 보이지 않는 ZERO WIDTH SPACE(U+200B)가 포함되어 있습니다. 일반적인 검색창이나 코드에서 "A B"를 찾으려고 하면 두 번째와 세 번째 문자열은 일치하지 않는 것으로 판정됩니다.

무조건 삭제하거나 치환하지 않아야 하는 이유

원인을 발견했다고 해서 데이터베이스나 텍스트 파일 전체에서 U+00A0나 U+200B를 일괄 삭제하는 것은 위험할 수 있습니다.

  • 단어 분리 훼손: NO-BREAK SPACE는 줄 바꿈을 막기 위해 단어 사이에 배치된 공백입니다. 이를 단순히 빈 문자열("")로 치환해 버리면 "A B"가 "AB"로 합쳐져 단어의 경계가 사라집니다.
  • 특정 언어 체계 파손: ZERO WIDTH SPACE는 크메르어나 태국어 등 띄어쓰기를 겉으로 드러내지 않는 언어권에서 단어 분절 및 줄 바꿈 처리를 위해 의도적으로 삽입하는 제어 문자입니다. 이를 무조건 지우면 텍스트의 분절 규칙이 깨질 수 있습니다.
  • 정규화 부작용: unicodedata.normalize('NFKD', ...)와 같은 호환성 분해를 적용하면 NBSP가 일반 공백으로 변환될 수 있지만, 동시에 분수 기호나 로마자 특수 표기 등 다른 중요한 기호까지 기본 글자로 풀어버릴 수 있으므로 주의가 필요합니다.

단계별 안전한 진단 및 정리 절차

검색이나 비교 오류가 발생했을 때는 다음 순서로 데이터를 다루는 것이 안전합니다.

  1. 검색 실패 문자열 격리: 일치하지 않는 검색 대상 단어와 비교 기준 단어를 각각 변수에 분리하여 저장합니다.
  2. 문자별 유니코드 이름 출력: unicodedata.name()을 활용해 두 문자열에서 글자 수와 각 글자의 코드 포인트를 출력하고, 어디에서 차이가 발생하는지 확인합니다.
  3. 필요성 검토 및 대상 한정: 발견된 숨은 문자가 웹 서식 복사로 인해 잘못 유입된 것인지, 본래 의미를 가진 문자열인지 확인합니다.
  4. 목적에 맞는 치환 적용: 웹 복사로 들어간 단순 띄어쓰기 목적의 NBSP라면 빈 문자열이 아닌 일반 공백(" ")으로 치환하고, 불필요하게 삽입된 U+200B만 지명하여 안전하게 제거합니다.
문자코드 포인트유니코드 이름권장 처리 방식
일반 공백U+0020SPACE유지 (필요 시 좌우 strip만 수행)
줄 바꿈 방지 공백U+00A0NO-BREAK SPACE단어 구분이 필요한 경우 일반 공백(U+0020)으로 변환
폭 없는 공백U+200BZERO WIDTH SPACE단어 분절 언어가 아니라면 선택적으로 제거

이 방법으로 확인할 수 없는 한계

코드 포인트와 유니코드 이름을 조회하는 방식은 현재 메모리에 올라온 개별 문자의 표준 규격 정보를 정확하게 보여줍니다. 그러나 다음과 같은 맥락적 문제는 판단해 주지 못합니다.

  • 해당 문자가 본래 업무 로직상 의도적으로 들어간 데이터인지, 단순히 잘못된 복사·붙여넣기로 발생한 오류인지 여부는 코드 분석만으로 알 수 없습니다.
  • 결합 문자(Combining Character)가 조합되어 시각적으로는 하나의 글자처럼 보이는 복합 글리프의 경우, 단순 문자 순회만으로는 분리된 결합 기호인지 단일 합성 문자인지 한눈에 파악하기 어렵습니다. 문자 인코딩 자체가 이미 변형되어 유입된 파일 오류는 한글 파일 깨짐: UTF-8 인코딩 확인하는 순서를 통해 파일 저장 단계부터 다시 추적해야 합니다.

참고 자료와 확인 범위

아래 자료는 형식·기능의 정의를 확인하는 데 사용했습니다. 본문의 예제와 설명은 이 사이트의 작업 상황에 맞춰 구성했습니다. 제품 메뉴는 버전과 언어에 따라 다를 수 있습니다.

확인일: 2026-10-18 · 오류를 발견하면 이 글의 오류 신고로 알려주세요.