Contents 호환성 문제의 정의와 증상 분류 즉시 조치 체크리스트(빠른 복구) 파일 형식별 특성과 선택 기준 버전 차이로 인한 기능 손실과 대체 전략 조직 환경 차이: 32/64비트, 추가기능, 보안 정책 CSV·텍스트 파일 호환성: 인코딩·구분 기호·서식 날짜·숫자 변형 방…
글 전체 보기- 공유 링크 만들기
- X
- 이메일
- 기타 앱
Contents 호환성 문제의 정의와 증상 분류 즉시 조치 체크리스트(빠른 복구) 파일 형식별 특성과 선택 기준 버전 차이로 인한 기능 손실과 대체 전략 조직 환경 차이: 32/64비트, 추가기능, 보안 정책 CSV·텍스트 파일 호환성: 인코딩·구분 기호·서식 날짜·숫자 변형 방…
글 전체 보기이 글의 목적은 엑셀에서 CLEAN/TRIM 함수로 공백이나 제어문자를 제거했는데도 텍스트가 정리되지 않을 때, 실제로 발생하는 모든 유형의 공백·특수문자를 진단하고 완벽하게 제거하는 표준 절차와 실무용 공식을 제공하는 것이다.
엑셀의 TRIM은 일반 공백(ASCII 32)을 연속 하나로 축소하고 앞뒤 공백을 제거하는 함수이다. CLEAN은 ASCII 0~31 범위의 인쇄 불가 제어문자를 제거한다. 웹·ERP·CRM에서 가져온 데이터에는 비분리공백(160), 얇은 비분리공백(8239), 제로폭 문자(8203, 65279), 탭(9), 줄바꿈(10, 13) 등 TRIM/CLEAN의 기본 대상이 아닌 코드 포인트가 혼재되어 있는 경우가 많다. 이 문자들은 화면에서는 보이지 않지만 비교·조인·피벗·중복 제거·수치 변환을 방해한다.
=LEN(A2) & " / " & LEN(TRIM(CLEAN(A2))) 두 값이 다르면 숨은 문자가 있는 것이다.
=IFERROR(UNICODE(LEFT(A2,1)),"") '첫 문자 코드 =IFERROR(UNICODE(RIGHT(A2,1)),"") '마지막 문자 코드 동적 배열을 사용해 전체 코드를 나열하면 원인이 명확해진다.
=LET(t,A2, arr, TEXTSPLIT(t,,SEQUENCE(LEN(t))), MAP(arr, LAMBDA(ch, IFERROR(UNICODE(ch), "")))) =LET(t,A2, s,SUBSTITUTE(SUBSTITUTE(SUBSTITUTE(t,CHAR(10),"⏎"),CHAR(13),"␍"),CHAR(9),"⇥"), s) 표시용 기호로 치환하여 육안으로 위치를 확인한다.
| 유형 | 코드 포인트 | 특징 | 기본 함수로 제거 여부 | 대응 공식 |
|---|---|---|---|---|
| 일반 공백 | 32 | 보통 스페이스 | TRIM 가능 | TRIM |
| 비분리공백(NBSP) | 160 | HTML | 불가 | SUBSTITUTE(,CHAR(160)," ") |
| 얇은 비분리공백(NNBSP) | 8239 | 프랑스어 구분자 | 불가 | SUBSTITUTE(,UNICHAR(8239)," ") |
| 제로폭 스페이스 | 8203 | 가시화 불가 | 불가 | SUBSTITUTE(,UNICHAR(8203),"") |
| 제로폭 넌조이너 | 8204 | 문자 조합 제어 | 불가 | SUBSTITUTE(,UNICHAR(8204),"") |
| 제로폭 조이너 | 8205 | 문자 조합 제어 | 불가 | SUBSTITUTE(,UNICHAR(8205),"") |
| 바이트 순서 표시(BOM) | 65279 | U+FEFF, 파일 선두 | 불가 | SUBSTITUTE(,UNICHAR(65279),"") |
| 탭 | 9 | 수평 탭 | CLEAN 불가 | SUBSTITUTE(,CHAR(9)," ") |
| 줄바꿈 | 10,13 | LF/CR | 부분적 | SUBSTITUTE(,CHAR(10)," "), SUBSTITUTE(,CHAR(13)," ") |
| 이상 공백(EN/EM SPACE 등) | 8192~8207 | 타이포그래피용 | 불가 | SUBSTITUTE(,UNICHAR(코드)," ") |
다음 LET 기반 공식은 실무에서 마주치는 대다수 숨은 공백·특수문자를 일괄 정규화한다.
=LET( t, A2, s1, SUBSTITUTE(t, CHAR(9), " "), /* 탭 → 공백 */ s2, SUBSTITUTE(s1, CHAR(10), " "), /* LF → 공백 */ s3, SUBSTITUTE(s2, CHAR(13), " "), /* CR → 공백 */ s4, SUBSTITUTE(s3, CHAR(160), " "), /* NBSP → 공백 */ s5, SUBSTITUTE(s4, UNICHAR(8239), " "), /* NNBSP → 공백 */ s6, SUBSTITUTE(s5, UNICHAR(8203), ""), /* zero-width space 제거 */ s7, SUBSTITUTE(s6, UNICHAR(8204), ""), /* ZWNJ 제거 */ s8, SUBSTITUTE(s7, UNICHAR(8205), ""), /* ZWJ 제거 */ s9, SUBSTITUTE(s8, UNICHAR(65279), ""), /* BOM 제거 */ s10, SUBSTITUTE(s9, UNICHAR(8192), " "), s11, SUBSTITUTE(s10, UNICHAR(8193), " "), s12, SUBSTITUTE(s11, UNICHAR(8194), " "), s13, SUBSTITUTE(s12, UNICHAR(8195), " "), s14, SUBSTITUTE(s13, UNICHAR(8196), " "), s15, SUBSTITUTE(s14, UNICHAR(8197), " "), s16, SUBSTITUTE(s15, UNICHAR(8198), " "), s17, SUBSTITUTE(s16, UNICHAR(8200), " "), s18, SUBSTITUTE(s17, UNICHAR(8201), " "), s19, SUBSTITUTE(s18, UNICHAR(8202), " "), TRIM(CLEAN(s19)) ) 쉼표 대신 세미콜론을 쓰는 지역 설정에서는 ,를 ;로 바꿔 사용한다.
이 공식을 이름 관리자에 등록하면 워크북 어디서나 간단히 호출할 수 있다.
이름: CLEANALL 참조: =LAMBDA(text, LET( t, text, s1, SUBSTITUTE(t, CHAR(9), " "), s2, SUBSTITUTE(s1, CHAR(10), " "), s3, SUBSTITUTE(s2, CHAR(13), " "), s4, SUBSTITUTE(s3, CHAR(160), " "), s5, SUBSTITUTE(s4, UNICHAR(8239), " "), s6, SUBSTITUTE(s5, UNICHAR(8203), ""), s7, SUBSTITUTE(s6, UNICHAR(8204), ""), s8, SUBSTITUTE(s7, UNICHAR(8205), ""), s9, SUBSTITUTE(s8, UNICHAR(65279), ""), s10, SUBSTITUTE(s9, UNICHAR(8192), " "), s11, SUBSTITUTE(s10, UNICHAR(8193), " "), s12, SUBSTITUTE(s11, UNICHAR(8194), " "), s13, SUBSTITUTE(s12, UNICHAR(8195), " "), s14, SUBSTITUTE(s13, UNICHAR(8196), " "), s15, SUBSTITUTE(s14, UNICHAR(8197), " "), s16, SUBSTITUTE(s15, UNICHAR(8198), " "), s17, SUBSTITUTE(s16, UNICHAR(8200), " "), s18, SUBSTITUTE(s17, UNICHAR(8201), " "), s19, SUBSTITUTE(s18, UNICHAR(8202), " "), TRIM(CLEAN(s19)) ) ) 사용 예:
=CLEANALL(A2) 숫자처럼 보이는 텍스트에 얇은 공백 또는 그룹 구분 기호가 섞인 경우 다음 템플릿으로 정규화 후 숫자화한다.
=LET( c, CLEANALL(A2), c1, SUBSTITUTE(c, ",", ""), /* 쉼표 제거(필요 시 지역 맞춤) */ c2, SUBSTITUTE(c1, UNICHAR(8239), ""), /* 얇은 비분리공백 제거 */ VALUE(c2) /* 숫자 변환 */ ) 반복 수집형 데이터는 Power Query 단계에 정리 로직을 포함하는 것이 유지보수 비용을 낮춘다.
Ctrl+J로 LF 입력, Alt+0010 등으로 제어문자를 명시 입력하여 공백으로 치환하다.M 코드 예시:
= Table.TransformColumns( Source, { {"TextCol", each let t1 = Text.Replace(_, Character.FromNumber(9), " "), t2 = Text.Replace(t1, Character.FromNumber(10), " "), t3 = Text.Replace(t2, Character.FromNumber(13), " "), t4 = Text.Replace(t3, Character.FromNumber(160), " "), t5 = Text.Remove(t4, {Character.FromNumber(8203), Character.FromNumber(8204), Character.FromNumber(8205), Character.FromNumber(65279)}), t6 = List.Accumulate({8192..8202}, t5, (state, c) => Text.Replace(state, Character.FromNumber(c), " ")) in Text.Clean(Text.Trim(t6)) , type text} } ) 구버전 엑셀이나 정규식이 필요한 상황에서는 다음 VBA 함수를 표준화하여 사용한다.
Option Explicit
Function CleanAllVBA(ByVal s As String) As String
Dim re As Object
Set re = CreateObject("VBScript.RegExp")
'모든 유니코드 공백(분리/비분리) 및 제어문자 제거/변환
'패턴 설명:
' \x{0009}\x{000A}\x{000D} 탭/LF/CR
' \x{00A0} NBSP
' \x{2000}-\x{200B} 다양한 유니코드 스페이스 및 제로폭
' \x{202F} 얇은 비분리공백
' \x{2060} WORD JOINER
' \x{FEFF} BOM
re.Pattern = "[\x{0009}\x{000A}\x{000D}\x{00A0}\x{2000}-\x{200B}\x{202F}\x{2060}\x{FEFF}]"
re.Global = True
re.IgnoreCase = True
re.Multiline = True
Dim t As String
t = s
'문단 구분자는 공백으로 표준화
t = Replace(t, vbCrLf, " ")
t = Replace(t, vbLf, " ")
t = Replace(t, vbCr, " ")
'유니코드 공백군과 제로폭 제거
t = re.Replace(t, " ")
'여분 공백 축소
t = WorksheetFunction.Trim(t)
CleanAllVBA = t
End Function
워크시트에서 =CleanAllVBA(A2)로 호출한다. 이 함수는 시스템에 VBScript.RegExp가 제공될 때 동작한다.
=LET(raw, A2, t, CLEANALL(raw), n, IFERROR(VALUE(SUBSTITUTE(t,",","")), t), n) 위 파이프라인은 텍스트 정리 후 숫자 변환을 시도하고 실패 시 원래 텍스트를 반환한다. 조인 키는 항상 정규화된 열을 생성하여 사용한다.
정규화 전후 동등성, 길이, 숫자 변환 가능성을 한 번에 검증하는 보고 열을 생성한다.
=LET( a, A2, b, CLEANALL(A2), ok_equal, a=b, len_before, LEN(a), len_after, LEN(b), as_num, IFERROR(VALUE(b),""), can_num, ISNUMBER(as_num), ok_equal & "|" & len_before & "→" & len_after & "|" & can_num ) TEXTSPLIT/TEXTBEFORE/TEXTAFTER 사용 전 CLEANALL을 먼저 적용하면 예기치 않은 빈 항목이나 분리 실패를 방지한다.
=TEXTSPLIT(CLEANALL(A2), ",") | 항목 | 점검 방법 | 합격 기준 |
|---|---|---|
| 숨은 문자 존재 | LEN vs LEN(TRIM(CLEAN)) 비교 | 동일해야 한다 |
| NBSP 포함 | FIND(CHAR(160)) | 없어야 한다 |
| 제로폭 문자 | UNICODE 스캔 | 없어야 한다 |
| BOM 제거 | LEFT 코드 포인트 확인 | U+FEFF 불검출 |
| 숫자 변환 성공 | ISNUMBER 검사 | TRUE |
두 함수는 ASCII 기반이다. NBSP(160), 얇은 NBSP(8239), 제로폭(8203 계열), BOM(65279) 등은 제거하지 못한다. 표준화 공식이나 LAMBDA를 사용해야 한다.
LEN은 유니코드 코드 포인트 수를 반환한다. 보이지 않는 문자도 길이에 포함되므로 TRIM/CLEAN 후 길이가 줄어드는 것이 정상이다.
보이지 않는 공백 외에 그룹 구분 기호, 비ASCII 마이너스(U+2212)와 같은 유사 문자도 제거해야 한다. SUBSTITUTE(,UNICHAR(8722),"-")를 추가한다.
반복 처리와 대량 데이터는 Power Query가 안정적이다. 단발성 정제나 사용자 주도 필터링은 워크시트 수식이 빠르다.
VBA 함수 CleanAllVBA를 사용하거나 Power Query로 처리한다.
쿼리 단계에서 정규화 규칙을 고정하고, 가져오기 연결을 새로 고침하도록 설정한다. BOM 처리 옵션을 확인한다.