오늘 배운 내용

백준에서 자바스크립트로 입력 받기

Node.js 'readline' 모듈

팀 자체적으로 매일 저녁 5시 30분부터 진행하는 알고리즘 스터디에서 백준 2667번 : 단지번호붙이기 문제풀이를 진행했다.

solution 함수 내부에 로직만 작성해야 하는 프로그래머스와 다르게 백준은 입력값을 입력해주는 처리를 따로 해주어야 했다. 프로그래머스와 리트코드처럼 스켈레톤이 편리하게 제공되는 플랫폼에 익숙해져있던 나에게는 입력 처리를 따로 해줘야 하는 점이 가장 불편하고 낯설게 다가왔다. 그렇지만 백준에는 정말 방대한 양의 알고리즘 문제가 있는걸? 꼭 그 문제들을 풀고 싶었다.

그래서 오늘은 자바스크립트로 입력 받는 법을 정리하면서 백준 플랫폼에 한결 익숙해지고자 한다.

검색을 해보니 자바스크립트로 입력을 받는 방법은 크게 두 가지가 있었다.

  • Node.js readline 모듈 사용
  • Node.js fileSysem 모듈 사용

오늘은 readline 모듈을 사용한 입력방법을 알아보자.

Node.js공식문서 에서는 readline 모율에 대해 다음과 같이 설명하고 있다.

The readline module provides an interface for reading data from a Readable stream (such as process.stdin) one line at a time.

모듈 불러오기

const readline = require('readline');

인터페이스 인스턴스 생성

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

The readline.createInterface() 매서드는 new readline.Interface 인스턴스를 생성해주는 매서드. 해당 인스턴스는 단일 input Readable stream 과 단일 output Writable stream 과 연결되어야 하기 때문에, 인스턴스 생성시에 현재 실행중인 Node.js 프로세스의 stdin과 stdout을 연결해준다.

'line' 이벤트 리스너 추가

줄을 끝내는 인풋(\n, \r, or \r\n)을 input stream이 받게되면, 'line'이벤트가 발생한다. 이 이벤트는 보통 유저가 엔터키를 누르거나 리턴을 할 때 발생한다.

입력된 각 줄은 리스너 함수에 input값으로 전달되어, 리스너 함수 조작을 통해 입려받은 input값을 처리할 수 있다.
우리같은 경우에는 보통 배열에 추가를 할테니, 다음과 같이 작성할 수 있겠다.

const arr = []
rl.on('line', (input) => {
  arr.push(input)
  console.log(arr)
});

여기까지 코드를 작성하고 나서 vsCode 를 연 뒤에, 터미널에서 해당 파일이 있는 디렉토리까지 이동을 하자.
그리고 나서 터미널에node 파일이름.js 를 치면, 다음과 같은 입력 란이 나올 것이다.

한 번 값을 입력해보자

한 줄 입력하고 Enter를 칠 때마다 'line'이벤트가 발생하여, 리스너 함수가 동작하는 모습을 볼 수 있다. 그리고 추가로 알 수 있는 점은 입력되는 값은 무조건 string타임이라는 것! 실제 코딩테스트에서 숫자 입력값이 주어지는 경우에는 입력을 받은 다음 map함수를 통해서 자료형을 변경해 주어야 하는 과정이 수반된다.

'close' 이벤트 리스너 추가

그런데 이렇게 신나게 입력값을 넣다보면 궁금한 점이 생긴다. "나 언제까지 입력해야 하는거야...?"
입력된 값을 가지고 이제 문제를 풀고 싶은데, 입력을 끊임없이 받는다.

입력을 종료하는 이벤트는 'close'이벤트이다. 해당 이벤트는 다음과 같은 상황에서 발동이 된다.

  • The rl.close() method is called
  • The input stream receives its 'end' event;
  • The input stream receives Ctrl+D to signal end-of-transmission (EOT);
  • The input stream receives Ctrl+C to signal SIGINT and there is no 'SIGINT' event listener - registered on the readline.Interface instance.
const readline = require("readline");
const rl = readline.createInterface({
	input: process.stdin,
	output: process.stdout,
});
const arr = [];
rl.on("line", (line) => {
	arr.push(line);
	console.log(arr);
	if (arr.length === 5) {
		rl.close();
	}
});

rl.on("close", function () {
	console.log(arr.length);
	console.log("입력 끝난다?");
});

위 코드에서는 5번의 input을 받고나서 rl.close()가 발동된다. 그리고 발동된 'close' 이벤트를 리스너가 감지하여 close 이벤트 리스너 함수가 실행된 모습을 볼 수 있다.

그래서 알고리즘 문제를 풀 때는, 'line'이벤트 함수 부분에는 입력 관련 로직을, 'close' 이벤트 리스너 함수 내부에는 문제 해결 로직을 작성하면 되겠다.

그런데 백준에서는 따로 rl.close() 를 호출해주지 않아도 동작한다.

process.exit() ?

그리고 close 이벤트가 마무리 될 때는 프로세스 종료를 명령하는 process.exit();을 적어주는데, 아무래도 close 이벤트 함수가 한 번 호출되어 실행되고 나면 더 이상의 입력은 없는 까닭에, 프로그램을 종료한다는 뜻으로 적어 주는 것 같다.

그런데 Node.js 문서에서는

The readline.Interface instance is finished once the 'close' event is emitted.

라고 적혀있는데... 그렇다면 close 이벤트는 프로그램 당 한 번이라는 이야기 아닌가? process.exit()을 사용하는 이유가 궁금하다.

재밌는건 Node.js fileSysem 모듈을 사용한 방법에서는 process.exit()을 적지 않는다는 점이다.

const readline = require("readline");
const rl = readline.createInterface({
	input: process.stdin,
	output: process.stdout,
});
const arr = [];
rl.on("line", (line) => {
	arr.push(line);
	console.log(arr);
});

rl.on("close", function () {
	console.log(arr.length);
	console.log("프로세스 끝난다?");
	//process.exit();
});

느낀 점

Javascript 로 백준 문제를 풀기에는 조금 불편했지만, 또 이렇게 Node.js 입출력에 대해 알 수 있는 기회가 되어 유익했다.

쓸모없는 지식은 없다.

원리를 알면 암기도 편해진다!

참조

profile
인사이트 있는 개발자가 되고 싶어요

0개의 댓글