JavaScirpt/Node.js

[Node.js] Starting Node.js with Crawling (character code, RegExp)

Tree_Park 2020. 12. 10. 13:26
728x90
문자 코드와 호환

- 문자 코드

  - 컴퓨터에서 문자를 표시하기 위해 대응하는 고유 번호, 문자에 할당된 번호

  - 웹 브라우저 위에 표시되는 많은 글들이 숫자의 나열[바이너리], 컴퓨터가 그 숫자의 나열을 문자로

    인식하여 표시

 

- 문자 코드가 어려운 이유

  - 알파벳과 숫자만 있다면 1byte로도 충분히 모든 문자가 표현이 가능하지만,

  - 한글이나 일본어, 중국어 등의 경우에는 문자의 수가 많아 2byte(0~65535)를 사용하지 않고서는

    모든 분자를 표현하는 것이 불가능하다.

  - 이들 언어의 문자를 컴퓨터상에서 다루기 위한 다양한 방법이 고안.

    - 다만 문제는 문자 코드 간의 호환성, 문자 코드의 인식에 실패하거나 문자 코드 간의 변환이 잘못되면

      이른바 '문자가 깨지는' 현상이 발생

 

- 현재의 주류 : 유니코드 (UNICODE)

  - 세계에서 사용되는 모든 문자를 공통의 문자 집합에 정의한 코드 체계

 

- 문자 집합과 부호화 스킴(CHRAACTER ENCODING SCHEME)

  - 유니코드에는 각 문자에 대한 코드 번호를 정의한 문자 집합과

  - 문자 집합을 어떻게 바이트 값으로 표시할지에 관한 문자 부호화 스킴이 정의되어 있다.

  

  - 문자 집합은 같아도 부호화 방식이 다를 수도 있다

    - 유니코드를 예로 들면, 유니코드를 2바이트로 표현한 것이 UTF-16이고 1바이트로 표현한 것이 UTF-8

    - 둘 다 유니코드의 문자 집합을 사용하고 있지만, 다른 부호화 방식을 사용하므로 텍스트를 바이너리로

      봤을 때는 다르게 보인다.

    - 같은 문자 집합을 사용하고 있으면 상호 간에 변환은 쉽다.

 

- 자바스크립트의 문자 코드

  - 내부적으로 UTF-16을 사용한다.

  - HTML의 문자 코드가 EUC-KR이라 해도 변환되어 UTF-16이 사용된다.

 

- Node.js의 경우

  - Node.js에서는 파일을 쓸 때 UTF-8을 기본으로 사용한다. 간단한 예로 fs 모듈을 사용하여

    UTF-8 텍스트 파일을 읽고 쓰는 프로그램을 만들어 볼 것이다.

 

코드

// read and write a file for Node.js
const fs = require('fs');

// read a file 'utf-8'
const text = fs.readFileSync("sample-utf8.txt","utf-8");
console.log(text);

// write a file as 'utf-8'
fs.writeFileSync("text.txt", text);

  - 파일을 동기적으로 읽는 fs.readFileSync() 메소드와 동기적으로 쓰는 fs.writeFileSync() 메소드를 사용

  - 읽고 쓰기를 할 때 옵션으로 문자 인코딩을 지정할 수 있고, 파일에 쓰기를 할 때에는 명시적으로

    utf-8을 지정하지 않아도 기본으로 utf-8로 데이터가 작성

  - 그러나 읽을 때는 utf-8을 지정하지 않으면 정상적인 결과를 얻을 수 없다.

 

// read and write a file for Node.js
const fs = require('fs');

// read a file 'utf-8'
const text = fs.readFileSync("sample-utf8.txt");
console.log(text);

// write a file as 'utf-8'
fs.writeFileSync("text.txt", text);

  - 텍스트를 읽을 때 문자 코드를 지정하지 않는 경우 결과는 Buffer 객체로 인식된다

  - <Buffer 73 61 6d 70 6c 65 0a>

  - fs.readFileSync() 메소드는 문자 코드 'EUC-KR'을 지원하지 않기 때문에, 실행 인자의 옵션으로

    'EUC-KR'을 지정하면 지원하지 않는 문자 코드라는 내용의 메시지가 뜬다.

 

- Node.js에서 문자 코드 변환

  - Node.js의 문자 표준 상태에서는 'EUC-KR'등의 문자 코드를 다룰 수 없으므로 외부 모듈을 설치 

  - 문자코드 변환에는 'iconv'라는 라이브러리가 널리 쓰인다.

    - 하지만 goormide는 패키지가 제대로 인식되지 않기 때문에 'iconv-lite'를 사용

  - 문자 코드의 자동 판정용 모듈 'jschardet'도 있다.

 

  - 설치 

    - npm install iconv-lite

    - npm install jschardet

 

코드

// read 'EUC-KR' file and then save to 'UTF-8' file.

const fs = require('fs');
const iconv = require('iconv-lite');

// write a text as 'euc-kr'
let str = "안녕하세요";
let fname = "iconv-lite-test-euckr.txt";

// convert to 'euc-kr'
let buf = iconv.encode(str, "euc-kr");

// save
fs.writeFileSync(fname, buf, "binary");

// display after reading a text of 'euc-kr'
let bin = fs.readFileSync(fname, "binary");

// convert binary of 'euc-kr' to 'utf-8'
let txt = iconv.decode(bin, 'euc-kr');
console.log(txt);

 

결과

Iconv-lite warning: decode()-ing strings is deprecated. Refer to https://github.com/ashtuchkin/ico

nv-lite/wiki/Use-Buffers-when-decoding

안녕하세요

  - 유의 사항은 위의 'decode()-ing string is deprecated'라는 출력문이다.

  - js의 type conversion 때문에, string의 경우 코드가 자동적으로

    - chunkBuffer.toString('utf8');로 변환되기 때문에 2중으로 디코딩되는 경우가 발생

  - 권장사항은

    - iconv.decode(Buffer.concat(chunks), 'utf-8');

  - 자세한 내용은 https://github.com/ashtuchkin/iconv-lite/wiki/Use-Buffers-when-decoding 참조

 

- 문자 코드를 모르는 텍스트를 읽는 경우

  - jschardet 모듈을 사용하여 문자 코드를 판정

코드

// read 'EUC-KR' file and then save to 'UTF-8' file.

const fs = require('fs');
const iconv = require('iconv-lite');
const jschardet = require('jschardet');


let fname = "iconv-lite-test-euckr.txt";

// read a unknown character code file
let buf = fs.readFileSync(fname);

// perform character code judgement
let det = jschardet.detect(buf);
console.log(det);

let buf2 = iconv.decode(buf, det.encoding);
let txt = buf2.toString('utf-8');
console.log(txt);

결과

{ encoding: 'EUC-KR', confidence: 0.6666666666666666 }
안녕하세요

 

정규표현식을 사용한 데이터 변환

- 정규 표현식

  - Regular Expression, 문자열의 패턴을 표현하는 표기 방법으로 문자열의 검색과 치환에 유용하다.

  - 문자열의 패턴을 메타 문자(미리 약속된 특별 기호)를 조합하여 표현함으로써 문자를 검색하거나 치환

 

- 자바스크립트에서의 정규표현식 사용법

  - 소스 코드 중에 '/패턴/'으로 정규표현식 객체를 생성가능.

    - let re = /value=\d+/; // 정규 표현식 리터럴

  - RegExp 객체를 생성하여 사용가능

    - let re = new RegExp("value=\d+");

 

  - 정규 표현식 리터럴을 사용하면 스크립트가 로드되는 시점에서 정규 표현식이 컴파일됨로

    성능에 유리하다.

  - RegExp 객체를 사용하면 문자열 변수로 정규 표현식 패턴을 지정할 수 있어 동적으로 정규표현식을

    다룰 수 있게 된다.

 

- 정규 표현식 메소드

메소드

설명

exec

문자열 중에서 일치하는 부분을 검색하여 결과를 반환한다. 검색에 실패한 경우 null을 반환한다 (RegExp의 메소드)

test

문자열 중에서 일치하는 부분이 있는지를 테스트한다. true/false 중 하나를 반환한다. (RegExp의 메소드)

match

문자열 중에서 일치하는 것을 검색하여 결과를 배열로 반환한다. 일치하는 패턴이 없는 경우 null을 반환한다. (String의 메소드)

search

문자열 중에서 일치하는 것이 있는지를 테스트한다. 일치하는 인덱스를 반환하거나 일치하는 부분이 없으면 -1을 반환한다. (String의 메소드)

replace

문자열 중에서 일치하는 것을 찾아서 다른 문자열로 치환한다.

split

문자열을 정규 표현식으로 분할하여 부분 문자열의 배열을 반환한다.

  - 어떤 문자열 안에 정규표현식 패턴이 있는지 확인만 하고 싶을 때

    - test() or search()

  - 더 자세한 정보를 알고 싶을 때

    - exec() or match()

 

- RegExp.exec()

  - 정규표현식에 해당하는 문자열을 검색하여 패턴이 존재하면 문자열의 배열을 반환함과 동시에

    RegExp 객체의 속성을 업데이트하고, 일치하는 패턴이 없으면 null을 반환한다.

  - 결과로 반환되는 배열에는 정규표현식에 일치하는 문자열이 첫 번째 요소에 담겨 있고, 이어서

    정규 표현식 중 괄호로 묶인 부분에 해당하는 부분문자열이 차례로 담겨있다.

  - 또한, 이 배열에는 속성으로 정규식에 해당하는 문자열의 인덱스 정보와 입력받은 문자열 값을

    포함하고 있다.

 

코드

> var re = /([0-9]+)([a-z+])/g;
> str = "111jpy,8usd,xxx";
'111jpy,8usd,xxx'
> console.log(re.exec(str))
null
undefined
> console.log(re.exec(str))
[
  '111j',
  '111',
  'j',
  index: 0,
  input: '111jpy,8usd,xxx',
  groups: undefined
]
undefined
> console.log(re.exec(str))
[
  '8u',
  '8',
  'u',
  index: 7,
  input: '111jpy,8usd,xxx',
  groups: undefined
]
undefined
> console.log(re.exec(str))
null
undefined

  - 지정한 정규표현식 패턴은 한 개 이상의 숫자에 이은 한 개 이상의 소문자 조합을 뜻한다.

  - 괄호가 두 번 사용되었는데, 각각 부분 패턴을 뜻한다.

 

  - 정규 표현식에 g플래그를 지정하면 문자열 안에 일치하는 모든 패턴을 포함하게 된다.

  - 위의 예에서는 exec()를 여러 번 호출하며 일치하는 패턴을 차례로 출력하고 있다.

  - exec() 메소드는 test()나 search()에 비해 실행속도가 느리므로 패턴의 존재 여부만을 확인하고

    싶은 경우엔 권장되지 않는다.

 

- RegExp.test() 메소드

  - 인자로 주어진 문자열에 정규표현식에 해당하는 문자열 패턴이 있는지 여부를 조사한다. 

    결과로 true나 false의 boolean 값을 반환한다

 

코드

> var re = /^\d{3}-\d{4}$/;
undefined
> re.test("123-1234");
true
> re.test("12-1234");
false
> re.test("440-0011");
true
> re.test("aaa-bbbb");
false

  - 자릿수가 부족한 "12-1234"는 false를 리턴한다.

 

- String.match() 메소드

  - String 객체에 준비된 match() 메소드는 인자로 전달받은 정규표현식 패턴을 조사한다.

    정규표현식에 g플래그를 포함하지 않은 경우는 RegExp.exec() 메소드와 같은 결과를 반환하지만

  - g플래그를 포함하는 경우에는 일치하는 부분을 모두 포함한 배열을 반환한다.

  - 일치하는 패턴이 없으면 null을 반환한다.

 

코드

> var str="v=20, n=40, c=30";
undefined
> str.match(/[0-9]+/);
[ '20', index: 2, input: 'v=20, n=40, c=30', groups: undefined ]
> str.match(/[0-9]+/g);
[ '20', '40', '30' ]
> str.match(/\w+=\d+/g)
[ 'v=20', 'n=40', 'c=30' ]

 

- String.search() 메소드

  - 대상 문자열에 정규표현식에 해당하는 패턴이 있는지 확인할 때 사용한다.

  - 정규표현식에 해당하는 패턴이 발견되면 발견된 인덱스를 돌려주고, 없으면 -1을 반환한다.

 

코드

> var str = "zip:999-9999, mail:a@example.com";
undefined
> str.search(/\d{3}-\d{4}/);
4
> str.search(/\w+\@\w+\.\w+/);
19
> str.search(/https?:\/\//);
-1

 

- String.replace() 메소드

  - 정규표현식으로 치환을 수행하는 replace() 메소드

  - 두 가지 형태의 사용법이 있다.

    - [서식1] 정규표현식을 이용한 치환 : str.replace(정규표현식 치환 될 문자열)

 

코드

> var str = "Today 10per OFF";
undefined
> str.replace(/\d+/, "30");
'Today 30per OFF'
> str.replace(/\d+[a-z]+/, "500yen");
'Today 500yen OFF'
> str.replace(/[a-zA-Z]+/g, "");
' 10 '

 

    - 치환될 문자열에 특수한 치환 패턴을 포함할 수 있다.

 

패턴

설명

$$

문자 ‘$’를 삽입한다

$&

매치된 부분 문자열을 삽입한다

$`

매치된 부분 문자열 직전의 문자열을 삽입한다.

$’

매치된 부분 문자열 직후의 문자열을 삽입한다.

$1$2$3

괄호로 묶인 부분 문자열을 삽입한다.

코드

> var str = "tel:045-111-222";
undefined
> str.replace(/(\d+)-(\d+)-(\d)/, "($1)-$2-$3");
'tel:(045)-111-222'

    - 콜백 함수를 사용하는 replace() 메소드를 살펴보자

    - [서식2] 콜백 함수를 사용하여 치환 : str.replace(정규표현식, 치환)

      - 문자열 str안의 정규 표현식에 일치하는 문자열에 대해 치환 함수가 수행된다.

        그러면 수행된 치환 함수의 반환 값으로 치환된다.

 

코드

str.replace(/[a-z]+/g, function(v) {
... return v.toUpperCase()
... });
'TEL:045-111-222'

> var str = "price: 100 won";
undefined
> str.replace(/\d+/, function(v) {
... v = parseInt(v);
... return Math.ceil(1.08 * v);
... });
'price: 108 won'

 

더 자세한 정규표현식은

https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/%EC%A0%95%EA%B7%9C%EC%8B%9D

 

정규 표현식

정규 표현식은 문자열에 나타는 특정 문자 조합과 대응시키기 위해 사용되는 패턴입니다. 자바스크립트에서, 정규 표현식 또한 객체입니다.  이 패턴들은 RegExp의 exec 메소드와 test 메소드  ,

developer.mozilla.org