D3.js 를 사용하여 데이터 시각화하기 #7 우리나라 지도 그리기(svg)
이스케이프 문자의 JSON Parse 오류에 대해 알아봅니다.
2019-03-23
Explanation
오늘은 이스케이프 문자가 JSON Parse 되는데 발생할 수 있는 오류에 관해서 적어보려고해요.
ES6에 템플릿 문자열 문법이 추가되었답니다. `(억음부호)를 사용해서 변수에 값을 선언할 수 있는 건데요. 예를 들면 아래와 같아요.
1 2 3 4 5 6 7 |
// ES6 이전 var data = '어서오세요'; var test = "안녕하세요.\n줄을 바꾸고\n" + data + " 반갑습니다."; console.log(test); // 안녕하세요. // 줄을 바꾸고 // 어서오세요 반갑습니다. |
1 2 3 4 5 6 7 8 9 |
// ES6 이후 const data = '어서오세요'; const test = `안녕하세요. 줄을 바꾸고 ${data} 반갑습니다.`; console.log(test); // 안녕하세요. // 줄을 바꾸고 // 어서오세요 반갑습니다. |
대략 이런식으로 사용할 수 있습니다.
우리는 JSON 객체를 이용해서 JSON 형태의 문자열을 객체로 만들거나 객체를 JSON 형태의 문자열로 바꿀 수 있습니다.
예를 들면 아래와 같아요.
1 2 3 4 5 6 |
const jsonString = "{\"dataKey\":\"dataValue\"}"; const jsonObj = JSON.parse(jsonString); console.log(jsonObj); // {dataKey : 'dataValue'} console.log(typeof jsonObj); // object |
1 2 3 4 5 6 |
const jsonObj = {dataKey: 'dataValue'}; const jsonString = JSON.stringify(jsonObj); console.log(jsonString); // {"dataKey":"dataValue"} console.log(typeof jsonString); // string |
JSON.stringify = 객체를 JSON 문자열로
JSON.parse = JSON 문자열을 객체로
처음에 이야기한 템플릿 리터널 문법을 사용하면 조금 더 편하게 JSON 문자열을 만들 수 있어요.
1 |
const jsonString = "{\"dataKey\":\"dataValue\"}"; |
1 |
const jsonString = `{"dataKey":"dataValue"}`; |
이스케이프 문자라는건 음… 백슬래사(\)를 사용해서 어떤 부호나 문자열을 본연의 뜻이 아니게 쓸 수 있게 한 걸 말하는데요.
위키백과: 이스케이프 문자는 이스케이프 시퀀스를 따르는 문자들로서 다음 문자가 특수 문자임을 알리는 백슬래시(\)를 사용한다.
위키백과: 이스케이프 시퀀스(escape sequence)는 컴퓨터와 주변 기기의 상태를 바꾸는 데에 쓰이는 일련의 문자열이다.
이야기하지 않았지만 앞선 예제에서 이미 이스케이프 문자를 사용하였답니다. jsonString이라는 변수를 초기화할때 “{\”dataKey\” … 이렇게 작성했었죠. 여기서 \” 이 부분을 이스케이프 문자라고 한답니다. 저기에 사용된 \” 이건 기존의 자바스크립트 언어에서 사용하는 “의 본연의 뜻과 다르게 문자열 자체의 “로 사용하게 되죠.
위에서 사용해본 큰따옴표 말고도 많은 이스케이프 문자가 있는데요. 대략 아래와 같은 것들이 있어요.
1 2 3 4 5 6 7 |
\' = 작은따옴표 \" = 큰따옴표 \/ = 슬래시 \\ = 역슬래시 \n = 뉴라인(개행) \t = 탭 ... |
여기에서는 이스케이프 문자중에 \n(개행)을 사용해서 예를 만들어 볼게요.
1 2 |
const jsonString = `{"key": "안녕하세요.\n줄을 바꾸고\n반갑습니다"}`; const jsonObj = JSON.parse(jsonString); |
위와 같은 코드는 어떻게 동작하게 될까요?
너무도 당연하게.. ‘저렇게 하면 안되지.’ 라고 생각하셨다면 전 작아집니다…
위 코드가 실행되면 SyntaxError가 발생한답니다. 왜냐면 JSON.parse 라는 메서드는 JSON 형태의 ‘문자열’ 을 객체로 바꿔주는 메서드인데 위 코드에 있는 \n 은 문자열이 아니고 이스케이프 문자이면서 개행을 의미하기 때문이에요.
그래서 위 코드가 동작하도록 수정하려면 아래와 같이 작성되어야 한답니다.
1 2 3 4 5 6 |
const jsonString = `{"key": "안녕하세요.\\n줄을 바꾸고\\n반갑습니다"}`; const jsonObj = JSON.parse(jsonString); console.log(jsonObj.key); //안녕하세요. //줄을 바꾸고 //반갑습니다 |
음… 그러니까… 앞선 오류가 이스케이프 문자여서라기 보다는 \n는 개행하는 이스케이프 시퀀스이기 때문에 JSON이 parse하기 위해 값을 읽을때 \n은 문자열이 아니여서 오류인거 같아요.
그래서 \\를 두번 사용해서 \(역슬래시)를 일반 문자열의 의미를 갖게 되고 그럼 자연스럽게 \\n은 개행의 의미를 갖지 않는 일반 문자열이 되고 정상적으로 parse가 진행되고 그 후에는 생각한대로 \n 개행이 포함된 문자열을 값으로 가지고 있는 객체가 만들어진답니다.
위에서 사용한 예를 이어서 사용해서,
1 |
const jsonString = `{"key": "안녕하세요.\n줄을 바꾸고\n반갑습니다"}`; |
위에 jsonString의 값을 JSON Parse 할 수 있는 문자열로 바꾸려고 할때, 정규표현식을 사용해서 수정을 하면 되는데요.
1 2 3 4 5 6 7 |
const jsonString = `{"key": "안녕하세요.\n줄을 바꾸고\n반갑습니다"}`; const replaceJsonString = jsonString.replace(/\n/g, '\\n'); const jsonObj = JSON.parse(replaceJsonString); console.log(jsonObj.key); //"안녕하세요. //줄을 바꾸고 //반갑습니다" |
이 역시 너무도 당연하게.. ‘저렇게 하면 되지.’ 라고 생각하셨다면 전 작아집니다…
여기서 헷갈릴 수 있는 부분은 정규표현식을 사용할때 ‘/\n/g’ 를 사용했는데 만약에 \n를 문자열로 생각해서 해당 문자열을 찾기 위해 ‘/\\n/g’ 를 사용하면 찾을 수 없다는 점이에요.
그리고 앞 예제 코드가 정상적으로 동작하는 건 ‘/\n/g’에서 \n을 있는 문자 그대로 찾았다고 생각하는 것보다 자바스크립트 정규표현식의 예약어?로 ‘\n’가 ‘줄 바꿈 문자에 대응’하도록 되어 있기 때문에 정상적으로 동작한다고 이해하는게 더 좋지 않을까 생각이 들었어요.
여기서 말한 정규표현식의 예약어는 예를 들면 \d = 모든 숫자에 대응, \D = 모든 숫자가 아닌 문자에 대응 이런 친구들을 이야기합니다.
참고.
https://ko.wikipedia.org/wiki/%EC%9D%B4%EC%8A%A4%EC%BC%80%EC%9D%B4%ED%94%84_%EB%AC%B8%EC%9E%90
https://abeldaos.tistory.com/4
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/%EC%A0%95%EA%B7%9C%EC%8B%9D
끝