トラック
/
JavaScript
JavaScript
/
演習
/
正規表現チャットボット
正規表現チャットボット

正規表現チャットボット

学習演習

はじめに

JavaScriptの正規表現

正規表現(Regex)とは、文字列の中の特定の要素を対象にして操作するために使える文字の並びです。これを使うと、次のことができます。

  • 文字列の中からテキストを検索する
  • 文字列の中の部分文字列を置換する
  • 文字列から情報を抽出する

💡 JavaScriptの正規表現の仕様は、この言語のECMA-262標準の一部です。つまり、ブラウザーごとの互換性を気にする必要はありません。

正規表現の作り方

JavaScriptでは、正規表現はたいてい/pattern/modifiersという形式で書きます。

正規表現を作る方法には、次の2つがあります。

  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があると、インデックスや入力などの役立つ情報とともに一致を1つだけ得る代わりに、配列に表示されるすべての出現箇所を返します。

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を開発している会社で正規表現スペシャリストとして雇われました。

開発はまだごく初期の段階なので、正規表現を使ってChatbotが自然言語を理解し、生成する能力を高めるのがあなたの使命です。

有効なコマンドをチェックする

Chatbotは賢いだけでなく、忠実なアシスタントでもあります。

Chatbotに何かを尋ねるときは、コマンドの先頭で「Chatbot」という単語を言う必要があります。

キーワードが大文字でも小文字でもかまいません。ここで重要なのは、その単語の位置です。

ユーザーがコマンドを出しているのかを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

暗号化された絵文字を削除する

Chatbotは、人間が感情を表すために絵文字をどう使うのかを理解するのが苦手です。

Chatbotがユーザーからのメッセージを受け取ると、それぞれの絵文字は「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"

有効な電話番号をチェックする

モバイルアプリでChatbotの機能をダウンロードすることを想定しているため、ユーザーは会話の中で電話番号を入力することが求められます。

問題は、Chatbotが特定の形式の番号しか読み取って検証できないことです。

番号が有効な場合(正規表現で指定された文字の並びに一致する場合)、Chatbotはユーザーに感謝し、番号を確認するメッセージで応答します。番号が無効な場合は、その電話番号は有効でないことを伝えます。

想定されている形式は次のとおりです:(+##) ###-###-###

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"

ウェブサイトのリンクを取得する

Chatbotはとても好奇心旺盛なソフトウェアです。特定のトピックについてインターネットで検索できても、関連する情報を探せるような、クールなウェブサイトやURLをユーザーに尋ねるのが好きです。

会話の例:

  • Chatbot: ねえusername、JavaScriptでコードを書く方法を学びたいんだけど、学べるいいウェブサイトを知らない?
  • User: exercism.orgからたくさん学びました

各ウェブサイトのリンクだけを含む配列を返すgetURL()関数を実装しましょう。どんなURLでも認識できる正規表現を書くのはとても複雑になりますが、Chatbotはシンプルな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"];

ユーザーに挨拶する

Chatbotと会話したすべての人のデータを保存するために、Chatbotはユーザーのプロフィールからフルネームをこの形式で取得できます:“smith, john”。

こうすることで、Chatbotに礼儀正しく、よい印象を与えてもらいたいと考えています。

ユーザーのフルネームが入った文字列を受け取り、文字列**“Nice to meet you, John Smith”**を返すniceToMeetYou()関数を書いてください。

学習のために、正規表現の置換メソッドを使ってこの関数を実装しましょう。

let str = 'Smith, John';

niceToMeetYou(str);
// => "Nice to meet you, John Smith"
GitHubで編集する リンクは新しいウィンドウまたはタブで開きます
JavaScript Exercism

正規表現チャットボットを始める準備はできましたか?

Exercismに登録すれば、37個のコンセプト159個の演習、そして本物の人間によるメンタリングとともに、JavaScriptを学んでマスターできます。すべて無料です。