곡선 따옴표가 코드, JSON, CSV를 망가뜨리는 이유

오류는 멀쩡해 보이는 줄을 가리킵니다. 차이가 눈에 보이지 않기 때문입니다.

곡선 따옴표(“ ” ‘ ’)는 프로그래밍 언어와 데이터 형식이 요구하는 직선 따옴표(" ')와 다른 Unicode 문자입니다. 파서는 정확한 코드 포인트를 비교하므로 곡선 따옴표는 그냥 일반 글자일 뿐이며 문자열이 열리지 않습니다. 직선 따옴표로 바꾸면 즉시 해결됩니다.

실제로 완전히 다른 문자입니다

문제의 전부를 한 표로 보여드리겠습니다.

문자 이름 코드 포인트
" 직선 큰따옴표 U+0022
왼쪽 큰따옴표 U+201C
오른쪽 큰따옴표 U+201D
' 직선 아포스트로피 U+0027
왼쪽 작은따옴표 U+2018
오른쪽 작은따옴표 U+2019

프로그래밍 언어, JSON, CSV, 셸 인터프리터는 이 중 정확히 두 개만 문자열 구분 기호로 인식합니다. 바로 U+0022와 U+0027입니다. 나머지 네 개는 알파벳이나 쉼표와 같은 부류의 평범한 인쇄 가능 문자입니다.

따라서 파서가 “name”을 만나면 약간 화려한 따옴표로 감싼 문자열로 보지 않습니다. 예상하지 못한 기호로 시작하는 따옴표 없는 문자열로 봅니다. 오류 메시지는 unexpected token 같은 내용으로 전혀 문제없어 보이는 줄을 가리키는데, 일반적인 글꼴 크기에서 "와 “의 차이는 곡률 몇 픽셀에 불과하기 때문입니다.

채팅에서 붙여넣기{ name: Ada }SyntaxError: Unexpected token '“'정규화 후{ "name": "Ada" }
곡선 따옴표는 파서가 기대하는 직선 따옴표와는 서로 다른 문자입니다.

어디에서 생겨나는가

거의 항상 소프트웨어가 친절을 베푼 결과입니다.

  • Word와 Google Docs는 입력하는 동안 직선 따옴표를 곡선 따옴표로 바꿉니다. 기본으로 켜져 있고 대부분의 사람은 알아차리지 못합니다. 산문에서는 원하는 동작이 맞기 때문입니다.
  • 채팅 모델은 제대로 조판된 출판물로 학습했기 때문에 곡선 따옴표를 생성합니다.
  • macOS는 많은 텍스트 필드에서 시스템 전역으로 스마트 치환을 적용합니다.
  • CMS 편집기와 댓글 입력창은 제출된 텍스트에 활자 필터를 적용하는 경우가 많습니다.
  • PDF 복사-붙여넣기는 조판에 사용된 것을 그대로 가져오는데, 전문적으로 제작된 문서라면 곡선 따옴표입니다.

공통점은 텍스트가 파싱을 위해 설계된 곳으로 가는 도중에 읽기를 위해 설계된 무언가를 거쳤다는 것입니다. 산문은 활자 따옴표를 원하고 코드는 정확한 바이트를 원합니다. 문제는 그 경계에서 일어납니다.

함께 알아둘 만한 몇 가지 동반자도 있습니다. 마침표 세 개 대신 말줄임표 문자(…), 하이픈 대신 en/em 대시, 일반 공백 대신 줄바꿈 없는 공백입니다. 각각 닮은 ASCII 문자와는 다른 코드 포인트이며, 각각 파서를 똑같이 조용한 방식으로 망가뜨립니다.

구체적으로 무엇이 망가지는가

JSON. JSON의 모든 문자열은 U+0022를 사용해야 합니다. 곡선 따옴표 하나면 문서 전체가 무효가 되고, 파서는 첫 번째 실패만 보고하기 때문에 수십 개가 있는 파일은 손으로 고치려면 여러 차례 반복해야 합니다. JSON 정리 및 검증 도구에 붙여넣으면 첫 번째 문제 문자의 정확한 위치를 보여줍니다.

CSV. 따옴표 규칙은 쉼표가 포함된 필드를 보호하기 위해 존재합니다. 곡선 따옴표는 따옴표 문자가 아니므로 “Smith, John” 같은 필드는 쉼표에서 분리되고 이후 모든 열이 한 칸씩 밀립니다. 이것은 구문 오류보다 더 치명적인데, 조용히 실패하기 때문입니다. 아무 불평 없이 가져와지는데 내용이 틀린 파일이 만들어집니다.

소스 코드. 대부분의 언어에서는 컴파일 또는 파싱 오류가 나는데, 그나마 소리라도 나는 편입니다. 셸 스크립트는 더 나쁠 수 있습니다. 하이픈 대신 en 대시가 들어간 rm –rf는 의도한 플래그가 아니며, 곡선 따옴표로 감싼 인수는 그대로 리터럴 텍스트로 전달됩니다.

설정 파일. YAML, TOML, .env 파일은 곡선 따옴표를 값의 일부로 조용히 받아들입니다. API 키에 장식용 문자가 붙고, 인증이 실패하고, 로그 어디에도 이유가 나오지 않습니다.

정규식과 검색. 직선 따옴표가 포함된 패턴은 곡선 따옴표가 포함된 텍스트와 일치하지 않으므로 찾아 바꾸기가 조용히 결과 0개를 반환합니다.

제대로 고치는 방법

텍스트를 정규화하세요. 곡선 따옴표를 직선 따옴표로 변환에 붙여넣으면 네 가지 곡선 변형을 모두 ASCII 문자로 바꾸고 변경한 개수를 알려줍니다. 특히 AI 출력물이라면 ChatGPT 및 AI 텍스트 정리가 따옴표와 함께 em 대시, 보이지 않는 문자, 이모지까지 한 번에 처리합니다.

원인을 끄세요. 이 문제가 계속 반복된다면 치환 기능을 비활성화하세요.

  • Word: 파일 → 옵션 → 언어 교정 → 자동 고침 옵션 → 입력 시 자동 서식 → "직선 따옴표를 곡선 따옴표로" 체크 해제.
  • Google Docs: 도구 → 환경설정 → "스마트 따옴표 사용" 체크 해제.
  • macOS: 시스템 설정 → 키보드 → 텍스트 입력 → 편집 → 스마트 따옴표 및 대시 끄기.

워드 프로세서에서 코드를 작성하지 마세요. 진짜 해결책은 구조적인 것입니다. 파서로 향할 텍스트는 문자를 임의로 바꾸지 않는 일반 텍스트 편집기에서 작성해야 합니다.

과도한 교정을 주의하세요. 산문에서 곡선 따옴표를 무조건 바꾸지는 마세요. 기사나 이메일에서는 활자 따옴표가 올바르고 직선 따옴표가 더 나빠 보입니다. 정규화는 경계에서, 즉 텍스트가 문서에서 코드나 데이터로 넘어갈 때만 하세요. 기본으로 모든 곳에 적용할 것이 아닙니다.

따옴표를 정규화한 후에도 파일이 계속 실패한다면 다음 용의자는 보이지 않는 문자입니다. 보이지 않는 Unicode 문자 안내를 참고하세요.

자주 묻는 질문

JSON이 멀쩡해 보이는데 unexpected token 오류가 나는 이유는 무엇인가요?

거의 항상 직선 따옴표가 있어야 할 자리에 곡선 따옴표가 있기 때문입니다. JSON은 정확히 U+0022를 요구하며, 곡선 변형인 U+201C와 U+201D는 파서에게 그냥 일반 문자입니다. 화면에서 차이가 몇 픽셀에 불과해서 해당 줄이 멀쩡해 보이는 것입니다.

곡선 따옴표와 직선 따옴표의 차이는 무엇인가요?

서로 다른 Unicode 문자입니다. 직선 따옴표는 U+0022와 U+0027로, 모든 파서가 기대하는 ASCII 문자입니다. 곡선 따옴표는 U+2018, U+2019, U+201C, U+201D로, 텍스트를 향해 휘어지는 활자 기호입니다. 산문에서는 올바르지만 문자열 구분 기호로는 무효입니다.

곡선 따옴표를 직선 따옴표로 어떻게 변환하나요?

곡선 따옴표를 직선 따옴표로 변환하는 도구 같은 정규화 도구에 텍스트를 붙여넣으면 네 가지 곡선 변형을 모두 바꾸고 개수를 알려줍니다. 찾아 바꾸기로 하려면 문자마다 한 번씩 총 네 번을 실행해야 해서 불완전하게 처리되기 쉽습니다.

CSV를 가져올 때 열이 밀리는 이유는 무엇인가요?

쉼표가 포함된 필드는 직선 따옴표로 감쌌을 때만 보호됩니다. 곡선 따옴표는 따옴표 문자가 아니므로 필드가 쉼표에서 분리되고 이후 모든 열이 밀립니다. 이 문제는 조용히 실패해서 깔끔하게 가져와지지만 내용이 틀린 파일이 만들어집니다.

곡선 따옴표를 항상 제거해야 하나요?

아니요. 산문에서는 올바른 활자이며 직선 따옴표보다 보기 좋습니다. 텍스트가 코드, JSON, CSV, 설정 파일 등 읽히는 것이 아니라 파싱되는 곳으로 넘어갈 때만 정규화하세요.

이 가이드에 소개된 도구

관련 가이드