트랙
/
JavaScript
JavaScript
/
연습 문제
/
정규식 챗봇
정규식 챗봇

정규식 챗봇

학습 연습 문제

소개

JavaScript의 정규 표현식

정규 표현식(또는 정규식)은 문자열에서 특정 요소를 지정하고 조작하는 데 사용하는 문자들의 나열이에요. 그래서 다음과 같은 일을 할 수 있어요.

  • 문자열에서 텍스트 검색하기
  • 문자열의 부분 문자열 바꾸기
  • 문자열에서 정보 추출하기

💡 JavaScript의 정규 표현식 문법은 이 언어의 ECMA-262 표준에 포함되어 있어요. 따라서 브라우저마다 다른 호환성을 걱정할 필요가 없어요.

정규 표현식을 만드는 방법

JavaScript에서 정규 표현식은 보통 /pattern/modifiers 형식으로 작성해요.

정규 표현식을 만드는 방법은 두 가지가 있어요.

  1. 정규 표현식 리터럴:
const regex = /[a-z]/;
  1. RegExp 생성자:
const regex = new RegExp('[a-z]');

두 경우 모두 JavaScript는 정규 표현식으로 객체를 만들어요. 기본적으로는 리터럴을 사용해 불변 패턴을 쓰는 것이 권장돼요.

RegExp 생성자는 정규 표현식이 바뀌거나 아직 무엇인지 모를 때(예를 들어 입력값처럼) 사용할 수 있어요.

🏴‍☠️ 플래그

정규 표현식에는 flags라고 하는 선택적인 초능력이 있어서 추가 기능을 사용할 수 있어요.

널리 사용되는 것들은 다음과 같아요.

  • /g - 전체 검색
  • /i - 대소문자 구분 없음
  • /m - 여러 줄 검색

간단한 예시를 볼까요.

const re = /home/gi;
const str = 'Home, sweet home.';
const myArray = str.match(re);
console.log(myArray);

=> // ["Home", "home"]

g 문자는 문자열 안에서 가능한 모든 일치 항목을 찾아내요. 이 기능이 없으면 JavaScript는 첫 번째 Home 일치만 추출해요.

대소문자 구분 없음 플래그 /i는 패턴을 찾을 때 유연하게 만들어 줘요. 덕분에 찾는 대상이 UPPERCASE이든 lowercase이든 상관없어요.

RegExp 생성자를 사용할 때는 플래그를 추가하는 문법이 달라요.

let regex = /[a-z]/gi; // literal notation
let regex = new RegExp('[a-z]', 'gi'); // constructor with string pattern as first argument
let regex = new RegExp(/[a-z]/, 'gi'); // constructor with regular expression literal as first argument (Starting with ECMAScript 6)

자주 쓰이는 함수

정규 표현식을 JavaScript의 내장 함수와 함께 사용하면 문자열을 조작하고 데이터를 얻는 강력한 방법을 쓸 수 있어요.

정규 표현식과 함께 자주 사용되는 함수 몇 가지를 소개할게요.

Test

test() 메서드는 정규 표현식과 지정된 문자열 사이의 일치를 검색해요. true 또는 false를 반환해요.

const str = 'It is difficult to test if you have a virus';
const result = /virus$/.test(str);

console.log(result);

// => true

Match

match() 메서드를 사용하면 찾은 일치 항목의 유무에 따라 내용이 달라지는 유용한 배열을 얻어요.

이렇게 해서 어떤 문자열에서든 정보를 검색하고 추출할 수 있어요. 예를 들어 볼까요.

const funnyQuote =
  'If you see someone crying, ask if it is because of their haircut.';
const regex1 = /someone/;
const regex2 = /happy/;

funnyQuote.match(regex1);
// => ["someone", index: 11, input: "If you see someone crying, ask if it is because of their haircut.", groups: undefined]

funnyQuote.match(regex2);
// => null

전체 검색 플래그 /g가 있으면, 인덱스나 입력값 같은 유용한 정보와 함께 하나의 일치 항목만 얻는 대신, 메서드는 배열에 표시된 모든 발생 항목을 반환해요.

const funnyQuote =
  'If you see someone crying, ask if it is because of their haircut.';

const regex3 = /if/gi;

funnyQuote.match(regex3);
// => ["If", "if"];

Replace

JavaScript의 replace() 메서드를 사용하면 주어진 문자열에서 값을 찾아 원하는 새 값으로 바꿀 수 있어요.

string.replace(searchValue, newValue);

대체할 대상을 찾는 패턴은 하나의 문자열일 수도 있고, 정규 표현식일 수도 있어요.

let string = 'I like dogs!';
let result = string.replace('dogs', 'cats');

let string = 'I would love to travel to Japan';
let result = string.replace(/Japan/g, 'Hawaii');

게다가 각 값에 추가적인 변경을 하기 위해 대체 위치에 함수를 적용할 수 있어요.

let text = 'Say hello to the chatbot.';
let result = text.replace(/chatbot|hello/gi, function (word) {
  return word.toUpperCase();
});
// => "Say HELLO to the CHATBOT"

Split

JavaScript의 split() 메서드는 정규 표현식으로 문자열을 사용하고 조작하는 또 다른 방법을 보여줘요.

이때 패턴을 인식해서 주어진 문자열을 나누는 데 정규식을 사용해요. 예를 들어 str.split(/[,.\s]/) 같은 식이에요. 이 패턴이 separator로 쓰여요.

const str = 'hello,user.how are.you';

const result = str.split(/[,.\s]/);

console.log(result);
// => ['hello', 'user', 'how', 'are', 'you']

지침

여러분은 챗봇을 개발하는 회사에 정규 표현식 전문가로 채용되었어요.

아직 개발의 아주 초기 단계라서, 정규 표현식을 사용해 챗봇이 자연어를 이해하고 생성하는 능력을 높이는 것이 이번 임무예요.

유효한 명령인지 확인하기

챗봇은 똑똑할 뿐만 아니라 충실한 비서이기도 해요.

챗봇에게 무언가를 물어보려면, 사용자는 명령의 맨 앞에 “Chatbot”이라는 단어를 말해야 해요.

키워드가 대문자든 소문자든 상관없어요. 여기서 중요한 것은 단어의 위치예요.

사용자가 명령을 내리고 있는지 챗봇이 알아볼 수 있도록 돕는 isValidCommand() 함수를 구현해요.

isValidCommand("Chatbot, play a song from the 80's.";
// => True
isValidCommand("Hey Chatbot, where is the closest pharmacy?";
// => False
isValidCommand("CHATBOT, do you have a solution for this challenge?";
// => True

암호화된 이모지 제거하기

챗봇은 사람들이 감정을 표현하려고 이모지를 어떻게 사용하는지 이해하는 데 어려움을 겪어요.

챗봇이 사용자 메시지를 받으면, 각 이모지는 “emoji” 뒤에 id 번호가 붙은 형태로 표현돼요.

문자열을 받아 메시지 전체에서 이모지 암호화 부분을 모두 제거하는 removeEmoji() 메서드를 구현해요.

이모지 텍스트가 들어 있지 않은 줄은 그대로 반환해야 해요.

이모지 문자열만 제거해요. 공백은 조정하려고 하지 마세요.

이 문제에서는 정규 표현식을 만들 때 생성자 문법을 사용해요.

removeEmoji("I love playing videogames emoji3465 it's one of my hobbies");
// => "I love playing videogames  it's one of my hobbies"

유효한 전화번호 확인하기

모바일 앱에서 챗봇 기능을 다운로드하는 상황을 고려해, 사용자는 대화 중에 전화번호를 입력하게 돼요.

문제는 챗봇이 특정 형식의 번호만 읽고 검증할 수 있다는 거예요.

번호가 유효하면(정규 표현식이 지정한 문자 시퀀스와 일치하면), 챗봇은 사용자에게 감사하고 번호를 확인하는 메시지로 답해요. 번호가 유효하지 않으면, 함수는 사용자에게 전화번호가 유효하지 않다고 알려줘요.

기대하는 형식은 다음과 같아요: (+##) ###-###-###

checkPhoneNumber('(+34) 659-771-594');
// => "Thanks! You can now download me to your phone."
checkPhoneNumber('659-771-594');
// => "Oops, it seems like I can't reach out to 659-771-594"

웹사이트 링크 가져오기

챗봇은 정말 호기심 많은 소프트웨어예요. 특정 주제에 대해 인터넷에서 검색할 수 있지만, 관련 정보를 찾을 멋진 웹사이트나 URL을 사용자에게 물어보는 것을 좋아해요.

대화 예시:

  • 챗봇: 안녕하세요 username님, 저는 JavaScript로 코딩하는 법을 배우고 싶어요. 배울 수 있는 멋진 웹사이트를 알고 있나요?
  • 사용자: 저는 exercism.org에서 많이 배웠어요

각 웹사이트의 링크만 담은 배열을 반환할 수 있는 getURL() 함수를 구현해요. 모든 URL을 인식하는 정규 표현식을 작성하는 것은 매우 복잡하겠지만, 챗봇은 간단한 URL만 읽으면 돼요. 이 연습 문제에서 URL은 "."로 구분된 단어의 나열이에요.

getURL(
  'I learned a lot from exercism.org and developer.mozilla.org, but I found ts39.es very boring!',
);
// => ["exercism.org", "developer.mozilla.org", "ts39.es"];

사용자에게 인사하기

대화한 모든 사람의 데이터를 저장하기 위해, 챗봇은 사용자 프로필에서 “smith, john” 형식으로 전체 이름을 가져올 수 있어요.

이렇게 해서 우리 챗봇이 정말 예의 바르고 좋은 인상을 주기를 바라요.

사용자의 전체 이름이 담긴 문자열을 받아 “Nice to meet you, John Smith” 문자열을 반환하는 niceToMeetYou() 함수를 작성해요.

학습을 위해, 정규 표현식의 치환 메서드를 사용해 함수를 구현해요.

let str = 'Smith, John';

niceToMeetYou(str);
// => "Nice to meet you, John Smith"
GitHub에서 편집 링크가 새 창이나 탭에서 열려요
JavaScript Exercism

정규식 챗봇 문제를 시작해 볼 준비가 됐나요?

Exercism에 가입하고 JavaScript 트랙을 개념 37개연습 문제 159개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.