Google スプレッドシートを使って文章を検証しよう

#はじめに
今年もアドベントカレンダーの季節がやってまいりました。
去年まではゲームアプリケーションで使用されるマスターデータを対象としたデータの検証方法を、Google Apps Scriptのコードやスプレッドシートの数式を用いて具体例を挙げながら解説してきましたが、最近では文章を対象とした検証ツールの作成を依頼されることも増えてきたため、今年のアドベントカレンダーは文章の検証ツールの作成を通して得られた知見を紹介して行きたいと思います。

過去に掲載した記事については下記のリンクをご参照ください。

[Google Apps Scriptを使ってみよう(前編)](https://qiita.com/omomukumamani_piroshi/items/beeb51d8c28369167cd9)
[Google Apps Scriptを使ってみよう(後編)](https://qiita.com/omomukumamani_piroshi/items/585c4478474b8d8c571c)
[Google Apps Scriptを使ってみよう(おまけ編)](https://qiita.com/omomukumamani_piroshi/items/03425833a0bdfc1249ca)
[カスタム関数でキャラクタースキルの詳細をチェックする]
(https://qiita.com/omomukumamani_piroshi/items/1ce62b2178af4aead494)
#自己紹介
2014年12月よりQAエンジニアとして、業務効率化や障害削減に関係するツール類の作成を主として業務を行なっています。最近は自然言語を対象に様々な言語に翻訳された文章を検証するツールを作成しています。

#今回紹介する内容
タイトルに記載した通り、今回はGoogle スプレッドシートを使って文章の検証を行う機能を作成して行きます。
文章と言っても色々とありますが、ここではゲームアプリケーションでよく見られるキャラクタースキルの説明文とそのキャラクタースキルを構成するマスターデータの内容が一致しているかの検証をどのようにして作成するか、順を追って説明します。

#想定される対象読者
* Google スプレッドシートを知っている。
* Google スプレッドシートは使ったことがないが、Microsoft Excelなら使ったことがある。
* 大体の数式はドキュメントを読みながら理解することができる。
* Google スプレッドシートを利用したマスターデータの検証に興味がある。

前置きが長くなりましたが早速始めましょう。

#今回の記事で使用する要件・仕様・設計
###要件
* マスターデータのスキル説明文とマスターデータに設定されるパラメータの内容を比較、検証できること。
* キャラクタースキルのIDを入力することで、検証結果表示を任意に指定できること。
* エラー内容は速やかに修正できるようにできるだけ詳細な内容を表示すること。
* キャラクタースキルの説明文は同じキャラクタースキルタイプの場合、効果値のみ変化する。
* 検証対象とするキャラクタースキルタイプは「ATK_UP,DEF_UP,SPD_UP」の3種類とする。

###要件をもとに作成した仕様
* 入力されたスキルIDをもとにマスターデータからキャラクタースキル名を表示。
* 入力されたスキルIDをもとにマスターデータのキャラクタースキルの説明文とマスターデータに設定されているパラメータが一致するかを検証。
* 検証結果をキャラクタースキルID、キャラクタースキル名と共に表示。
* 検証結果がNGの場合には速やかに修正が可能なように、検証結果がNGであることとその内容を表示する。
* キャラクタースキルの説明文は同じキャラクタースキルタイプの場合、効果値のみ変化することから、説明文の効果値以外の部分がキャラクタースキルタイプと一致するかをまず検証し、次に効果値が一致するかを検証する。
* 検証結果が正しい場合には「OK」を、期待されない結果であった場合には「NG:」を接頭辞として以降にその内容を出力する。

###設計
**検証結果シート**
* キャラクタースキルIDを入力。
* キャラクタースキルIDをもとにキャラクタースキル名を出力
* キャラクタースキル説明文の内容とマスターデータに設定されているパラメータを比較・検証を行った結果を検証結果に出力

|キャラクタースキルID|キャラクタースキル名|検証結果|
|:-:|:-:|:-:|
|入力|出力|出力|

**検証用マスタシート**
* キャラクタースキルのマスターデータ入力用シート

|キャラクタースキルID|キャラクタースキル名|キャラクタースキルタイプ|効果値|キャラクタースキル説明文|
|:-:|:-:|:-:|:-:|:-:|
|スキルを識別するID(数値)|名称(文字列)|スキル効果のタイプ(文字列)|効果の大きさ(数値)|内容の説明(文字列)|

**説明文テンプレシート**
* 同じキャラクタースキルタイプ内では効果値のみ変化する仕様から、キャラクタースキルタイプごとに固定の文言の箇所と効果値により変化する部分を検証できるように、正規表現を用意する。

|キャラクタースキルタイプ|検証用テンプレート|
|:-:|:-:|
|スキル効果のタイプ(文字列)|正規表現(文字列)|

**tmp_検証用マスタシート**
* 検証用マスタシートに定義済みのマスターデータを参照し、検証しやすい形式に整形するためのシート。
* 整形した後のデータを使用して検証を行い、検証結果シートで結果表示を行えるようにする。
* 構成については後ほど解説中に行います。

###準備

**検証用マスタシートの準備**
検証を行うためにはまず検証対象となるテストデータが必要になります。
設計の検証用マスタシートで定義した項目でマスターデータを用意しましょう。
今回は準備の段階で用意するマスターデータにすでにいくつか設定のミスを組み込んであります。
ミスに気がついても後の説明で使用するためそのままで大丈夫です。

スプレッドシートに「検証用マスタ」という名前のシートを作成し、下記のリストを「B2:F8」の範囲に入力(もしくはコピー)します。

|キャラクタースキルID|キャラクタースキル名|キャラクタースキルタイプ|効果値|キャラクタースキル説明文|
|-:|:-|:-|-:|:-|
|1|攻撃力アップ(大)|ATK_UP|100|攻撃力が100アップする|
|2|攻撃力アップ(小)|ATK_UP|20|防御力が20アップする|
|3|防御力アップ(大)|DEF_UP|50|防御力が80アップする|
|4|防御力アップ(小)|DEF_DOWN|10|防御力が10アップする|
|5|素早さアップ(大)|SPD_UP|15|素早さが15アップする|
|6|素早さアップ(小)|SPD_UP|5|素早さが5アップする|

<img width="700" alt="検証用マスタ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/eccc5f9b-65a9-bac4-02f3-e8772f865aa6.png">

**説明文テンプレシートの準備**
次に検証を行うためのデータを用意します。
仕様には**「キャラクタースキルの説明文は同じキャラクタースキルタイプの場合、効果値のみ変化することから、説明文の効果値以外の部分がキャラクタースキルタイプと一致するかをまず検証し、次に効果値が一致するかを検証する」**とありました。
今回はこの仕様を満たすために正規表現を使用します。
正規表現が何かについての詳しい説明は割愛しますが、**「様々な文字列を一つの形式で表現するもの」**と考えていただければ良いかと思います。
今回の例では「(.\*?)」という表記のみを使用します。簡単に説明すると「(.*?)」は直前に指定された文字(列)と直後に指定された文字(列)に挟まれた、任意の1文字の0回以上の繰り返した部分を取得する、という表現になります。
先ほどのキャラクタースキル説明文を見ると全て「攻撃力が/防御力が/素早さが〇〇アップする」という構造でできているため、攻撃力が or 防御力が or 素早さが、という文字列と、アップという文字列に挟まれた、〇〇に該当する文字列を取得するために「(.\*?)」という表記を使用します。

正規表現について詳しく知りたい方は「[正規表現（regex）について](https://support.google.com/analytics/answer/1034324?hl=ja)」を参照してください。

正規表現の話はここまでとして先に進めます。
スプレッドシートに「説明文テンプレ」という名前のシートを作成し、下記のリストを「B2:C5」の範囲に入力(もしくはコピー)します。

|キャラクタースキルタイプ|検証用テンプレート|
|:-|:-|
|ATK_UP|攻撃力が(.*?)アップ|
|DEF_UP|防御力が(.*?)アップ|
|SPD_UP|素早さが(.*?)アップ|

<img width="400" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/6b638dcf-c07b-99f9-9751-f653efb9a141.png">

**検証結果シートの準備**

検証対象になるキャラクタースキルIDを入力すると、検証対象になるキャラクタースキル名と検証結果が表示されるシートになります。
機能については後ほど実装していくのでここでは表示用のヘッダーだけ用意します。
スプレッドシートに「検証結果」という名前のシートを作成し、下記のリストを「B2:D2」の範囲に入力(もしくはコピー)します。

|テスト対象のキャラクタースキルID|キャラクタースキル名|検証結果|
|:-|:-|:-|

<img width="700" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/08aa2d9c-a8a5-bfee-9154-87a1393f863a.png">

**tmp_検証用マスタシートの準備**

シートの準備はこれで最後になります。
このシートは他のシートを参照したり、実際に検証を行う数式を入力していくことになるため、空のシートを用意します。
スプレッドシートに「tmp_検証用マスタ」という名前のシートを作成します。
これで準備が整いました。

##実装
####実装方針
実際に検証機能を実装していきますが、実装する方針を改めてまとめます。
1. 検証用マスタシートからマスターデータを全て取得する。
2. 取得したキャラクタースキルのキャラクタースキルタイプに併せて検証用テンプレシートから正規表現を取得する。(取得できなかったキャラクタースキルタイプについては取得できなかった旨をエラーメッセージとして表示する。)
3. 2の手順で取得した正規表現を使用して、効果値を取得する。効果値を取得できなかった場合にはその旨をエラーメッセージとして表示する。(2の手順で取得できなかった場合は2のエラーメッセージを表示する。)
4. キャラクタースキルに設定されている効果値と3の手順で取得した値を比較して検証を行う。一致する場合には「OK」を、一致しない場合にはその旨をエラーメッセージとして表示する。(2,3の手順でエラーが発生している場合にはそのエラーメッセージを表示する。)
5.検証結果シートに入力されたキャラクタースキルIDをもとに、キャラクタースキル名と1~4の手順で検証を行った結果を表示する。

上記の手順で実装を行なっていきます。

####1. 検証用マスタシートからマスターデータを全て取得する。
これについては色々と方法がありますが、今回は[query](https://support.google.com/docs/answer/3093343?hl=ja)という数式を使用します。この数式は指定した範囲にあるセルのデータを条件に従って取得します。
今回の例では単に取得する目的で使用するため、詳細な理解は必要ありません。

下記の数式をtmp_検証用マスタのB3へ入力します。
`=query('検証用マスタ'!B1:F,"select *")`

SQLなどを使ったことがある方にはわかりやすい内容かもしれません。
queryはひとつめの引数に範囲を、ふたつめの引数に取得する条件を指定します。
B2のセルと罫線、オレンジに着色されている箇所は見た目の違いなので、お好みで調整してください。
下記の画像のようにキャラクタースキルマスタの内容が取得できたでしょうか。
<img width="800" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/bc9f2bcf-e6ab-8c18-169e-777e2ab2d39f.png">

####2. 検証用テンプレシートから正規表現を取得する。
仕様には**「キャラクタースキルの説明文は同じキャラクタースキルタイプの場合、効果値のみ変化することから、説明文の効果値以外の部分がキャラクタースキルタイプと一致するかをまず検証し、次に効果値が一致するかを検証する。」**とあったため、1の手順で取得したキャラクタースキルマスタに設定されているキャラクタースキルタイプをもとに、検証用テンプレシートから検証用の正規表現を取得します。
今回は[VLOOKUP](https://support.google.com/docs/answer/3093318?hl=ja)を使用します。この数式は少し説明が難しいのですが、ひとつめの引数で指定した値を使用して、ふたつめの引数で指定した範囲の1列目を検索します。最初に一致した行で指定した範囲の先頭列を1としてみっつめの引数で指定した値の列にあるデータを取得するという数式です。

`=VLOOKUP(D4, '説明文テンプレ'!B$3:C, 2, false)`
この数式を検証用テンプレシートを見ながら説明します。

||B|C|
|:-|:-|:-|
|2|キャラクタースキルタイプ|検証用テンプレート|
|3|ATK_UP|攻撃力が(.*?)アップ|
|4|DEF_UP|防御力が(.*?)アップ|
|5|SPD_UP|素早さが(.*?)アップ|

D4の値がATK_UPだった場合、検証用テンプレのB3:Cを範囲としてB列にATK_UPがあるかを検索します。
3行目に見つかったため、B列を先頭行として2列目の「攻撃力が(.\*?)アップ」を取得する。というのがVLOOKUPの動作です。
数式に指定する最後のfalseについては、検索対象の行が並べ替えられているかどうかを指定しますが、通常はtrueを指定することがあまりなくfalseとした方が正常に動作することが多いです。
またひとつめの引数に指定した値がB列に見つからなかった場合、VLOOKUPはエラーを返します。
実装方針では、**「取得できなかったキャラクタースキルタイプについては取得できなかった旨をエラーメッセージとして表示する」**という内容も含まれていました。
VLOOKUPをはじめとして、数式がエラーを返したかを判定する[IFERROR](https://support.google.com/docs/answer/3093304?hl=ja)があります。
IFERRORはふたつの引数を指定します。
ひとつめはエラーを返すか判定したい数式、ふたつめはエラーを返したときにエラーの代わりに返したい値となります。ひとつめの引数で渡した数式がエラーを返さない場合は、数式の結果が返されます。

前述のVLOOKUPの数式でエラーの判定を行いたいので、IFERRORのひとつめの引数に指定します。
ふたつめの引数はエラーと判定されたときに表示したい内容を渡します。
エラーの内容の表示するときは接頭辞に「NG:」をつけるという仕様だったのでその内容で出力します。

`=IFERROR(VLOOKUP(D4,'説明文テンプレ'!$B$3:C,2,false),"NG: スキルタイプに対応する説明文テンプレが見つからない。[スキルタイプ:"&D4&"]")`

上記の数式で2番目の実装方針であった、**「取得したキャラクタースキルのキャラクタースキルタイプに併せて検証用テンプレシートから正規表現を取得する。(取得できなかったキャラクタースキルタイプについては取得できなかった旨をエラーメッセージとして表示する。)」**を満たすことができます。

上記の「=IFERROR」で始まる数式を、tmp_検証用マスタシートのG4のセルへ入力します。
下記の画像のように表示されたでしょうか。
<img width="600" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/0c6002f8-2079-5500-668b-e6a4c9c6d3d5.png">

また、このままだと一番上の行しか数式が有効ではないため、G9まで数式を有効にする必要があります。
G4のセルをクリックで選択します。
<img width="600" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/3ddd3f70-0afc-5938-3fea-13d52157c9cb.png">

選択したセルの右下に少し大きめに■が表示されているのがわかると思います。
この■をG9のセルのあたりまでドラッグして離します。
<img width="600" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/5f962ed8-4edc-a900-d89a-eac311e09bb2.png">

この操作をオートフィルと呼びます。
この後も使用するので覚えておいてください。

さて、画像を見ると先ほどの数式で用意したエラー表記が確認できます。
キャラクタースキルタイプをもとに正規表現を取得する数式で、一致するスキルタイプが見つからない場合に表示するエラーメッセージだったので、検証用マスタシートのキャラクタースキルタイプを確認しましょう。

|キャラクタースキルID|キャラクタースキル名|キャラクタースキルタイプ|効果値|キャラクタースキル説明文|
|-:|:-|:-|-:|:-|
|4|防御力アップ(小)|DEF_DOWN|10|防御力が10アップする|

該当するデータが見つかりました。
今回の要件には、検証対象とするキャラクタースキルタイプは「ATK_UP,DEF_UP,SPD_UP」の3種類とあったのでエラーメッセージを表示するところで一旦終了です。

####3. 正規表現を使用して、効果値を取得する。
キャラクタースキルタイプに対応する正規表現が取得できたところで、実際に正規表現を使用して効果値の取得を行います。取得するために使用する数式は[REGEXEXTRACT](https://support.google.com/docs/answer/3098244?hl=ja)です。
REGEXEXTRACTにはふたつの引数を指定します。
ひとつめの引数は対象になる文字列、ふたつめは正規表現です。
REGEXEXTRACTは本来、対象になる文字列の中で正規表現に一致する部分を取得する、という数式ですが、今回使用する正規表現は全て「（）」（丸括弧)が含まれています。
正規表現ではこの丸括弧のことをキャプチャグループと呼び、REGEXEXTRACTの正規表現にキャプチャグループが指定されている場合、正規表現に一致する部分の中でさらにキャプチャグループと一致する部分を取得するように機能が変化します。

`=REGEXEXTRACT(F4,G4)`

この数式をtmp_検証用マスタを見ながら説明します。

||F|G|
|:-|:-|:-|
|3| キャラクタースキル説明文|説明文テンプレ|
|4|攻撃力が100アップする|攻撃力が(.*?)アップ|

F4の内容が対象になる文字列、G4の内容が正規表現です。
正規表現は、「攻撃力が」と「アップ」に挟まれた部分の任意の1文字以上の0回以上の繰り返しを取得する、という内容でした。
このため対象文字列の中の「100」に該当する部分がREGEXEXTRACTで取得されます。

またこのREGEXEXTRACTについて、VLOOKUPで該当する値が見つからなかった場合にエラーを返すのと同様に、正規表現で一致する表記が見つからなかった場合にエラーを返します。
そのためVLOOKUPでエラーが発生した場合と同様にIFERRORを使用して、正規表現と一致する部分が見つからなかった場合のエラーメッセージを用意します。

`=IFERROR(REGEXEXTRACT(F4,G4),"NG: 説明文テンプレで説明文に含まれる値が取得できない。[説明文テンプレ:"&G4&"][説明文:"&F4&"]")`

IFERRORの使い方はVLOOKUPのときと同様です。
ひとつめの引数にエラーがあるかを判定したい数式を、ふたつめの引数にはエラーが発生した場合に返す内容を入力します。

さらに実装方針を確認すると、**「(2の手順で取得できなかった場合は2のエラーメッセージを表示する。)」**と記載がありますのでこの内容についても実装します。
2の手順ではキャラクタースキルタイプをもとに正規表現を取得しましたが、正規表現が取得できなかった場合にはエラーメッセージを出力する仕様でした。いずれにせよ結果の値はG列に出力されるため、REGEXEXTRACTで説明文に含まれる値を取得する処理の前に、G列の値がエラーメッセージであるかを調べます。仮にエラーメッセージであった場合にはその内容をそのまま使用し、エラーメッセージ出なかった場合には値を取得する処理を行うように数式を実装します。
エラーメッセージには接頭辞に「NG:」が共通で含まれるため、[REGEXMATCH](https://support.google.com/docs/answer/3098292?hl=ja)を使用して判定します。
REGEXMATCHはふたつの引数を指定します。
ひとつめの引数は対象となる文字列を、ふたつめの引数は正規表現を指定します。
対象になる文字列中に正規表現に一致する部分が見つかった場合、REGEXMATCHはTRUEを返し、見つからなかった場合にはFALSEを返します。[IF](https://support.google.com/docs/answer/3093364?hl=ja)とREGEXMATCHを使ったエラーメッセージの判定、それに先ほど説明したREGEXEXTRACTを使用した値を取得する数式を組み合わせて実装します。

数式が複雑になるため、はじめに各数式を日本語に置き換え処理のされ方を理解した後に、少しずつ数式へ置き換えます。

1.IF数式を日本語で記述する
`=IF({G4の内容に「NG:」が含まれるかを判定する処理}, {含まれているのでG4を出力}, {値を取り出す数式})`

2.G4がエラーメッセージかを判定する部分と、エラーメッセージであった場合にG4を返す部分を数式にする
`=IF(REGEXMATCH(G4,"NG:"), G4, {値を取り出す数式})`

3.正規表現で値を取得する部分を数式で置き換える
`=IF(REGEXMATCH(G4,"NG:"), G4, IFERROR(REGEXEXTRACT(F4,G4),"NG: 説明文テンプレで説明文に含まれる値が取得できない。[説明文テンプレ:"&G4&"][説明文:"&F4&"]"))`

1~3の手順を行うことで3番目の実装方針であった**2の手順で取得した正規表現を使用して、効果値を取得する。効果値を取得できなかった場合にはその旨をエラーメッセージとして表示する。(2の手順で取得できなかった場合は2のエラーメッセージを表示する。)**を満たすことができます。

上記の3番目の手順にある数式を、tmp_検証用マスタシートのH4のセルへ入力し、H9までオートフィルで数式をコピーします。
下記の画像のように表示されたでしょうか。
<img width="800" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/c04ba074-c71d-1a67-011e-ae6f1292bea3.png">

さて、画像を見ると数式で用意したふたつのエラー表記が確認できます。
H7は正規表現が入るはずのセルにエラーメッセージが入っている時に表示されるように実装したものです。
もう一つのH5はREGEXEXTRACTで、正規表現で一致する表現が見つからない場合に表示されるメッセージとして実装したものでした。
画像中のF5を対象の文字列としてG6の正規表現で検証した結果、「防御力が80アップする」という文字列に、「攻撃力が」と「アップ」に挟まれる部分が見つからないため値が取得できない、という内容のエラーメッセージが表示されています。
この実装により、実装方針の3番目を満たすことが確認できたため、次の実装へ進みます。

####4. キャラクタースキルに設定されている効果値と説明文から取得した値を比較して検証を行う。
正規表現で取得できた説明文の中に出てくる値とキャラクタースキルに設定されている効果値を比較して検証を行います。これまでのように難しい数式は使用しません。
説明文の中から取得した値は数値ではなくテキストとして扱われる場合があるため単純に比較すると、見た目上同じように見えても異なるものとして扱われた結果、一致しないという結果になることがあります。
そのため数値に変換するための数式である[value](https://support.google.com/docs/answer/3094220?hl=ja)を使用して数値に変換した後にIF数式を使用して比較を行います。
値が一致する場合には「OK」を、一致しない場合には「NG:」を接頭辞として以降に一致しない旨を表示します。

`=IF(value(E4)=value(H4),"OK","NG: 効果値と説明文に含まれる値が一致しない。[効果値:"&E4&"][説明文の値:"&H4&"]")`

また、これまでと同様にH4にはエラーメッセージが入っていることもあるので、REGEXMATCHを使用して「NG:」が含まれているかを判定し、含まれている場合にはそのエラーメッセージを返し、含まれていない場合には先ほどの値を比較する数式を実行するように、実装を行います。

1.IF数式を日本語で記述する
`=IF({H4の内容に「NG:」が含まれるかを判定する処理}, {含まれているのでH4を出力}, {値を検証する数式})`

2.H4がエラーメッセージかを判定する部分と、エラーメッセージであった場合にH4を返す部分を数式にする
`=IF(REGEXMATCH(H4,"NG:"), H4, {値を検証する数式})`

3.値を検証する部分を数式で置き換える
`=IF(REGEXMATCH(H4,"NG:"), H4, IF(VALUE(E4)=VALUE(H4),"OK","NG: 効果値と説明文に含まれる値が一致しない。[効果値:"&E4&"][説明文の値:"&H4&"]")`

1~3の手順を行うことで4番目の実装方針であった**「キャラクタースキルに設定されている効果値と3の手順で取得した値を比較して検証を行う。一致する場合には「OK」を、一致しない場合にはその旨をエラーメッセージとして表示する。(2,3の手順でエラーが発生している場合にはそのエラーメッセージを表示する。)」**を満たすことができます。

上記の3番目の手順にある数式を、tmp_検証用マスタシートのI4のセルへ入力し、I9までオートフィルで数式をコピーします。
画像ではF,G列が非表示になっていますがI列は画像のように表示されたでしょうか。

<img width="800" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/98b62abc-2e07-a3a9-9ac7-02fc051a0d7d.png">

さて、画像を見ると3つのエラー表記が確認できます。
I5のセルとI7のセルには先ほど説明した、キャラクタースキルタイプから正規表現を取得できなかった場合のエラーと正規表現で値の取得に失敗した際のエラーメッセージが表示されています。
I6のセルには新しいエラーメッセージが表示されています。
E6とH6のセルの内容を比較した結果、値が一致しなかったためその内容が表示されています。
この実装により、全ての実装方針を満たすことが確認できたため、最後に検証結果シートの実装を行います。

####5. 検証結果シートに検証を行った結果を表示する
最後に検証結果シートへ検証の結果を表示する実装を行います。
要件をもとに作成した仕様には**「検証結果をキャラクタースキルID、キャラクタースキル名と共に表示。」**とありました。また、実装方針でも**「検証結果シートに入力されたキャラクタースキルIDをもとに、キャラクタースキル名と1~4の手順で検証を行った結果を表示する。」**としていたため、ここでは**入力されたキャラクタースキルマスタのIDが見つからなかった場合**のみを考慮してエラー処理を行います。

下記の画像はこれまでの手順で作成したtmp_検証用マスタになります。
<img width="800" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/e712183d-8b4c-1753-852d-12922c54a7e5.png">

そしてこちらが検証結果を表示する、検証結果シートになります。
<img width="800" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/8c05a206-be0a-5fb9-0333-cd1b03ef8262.png">

指定した値をもとに範囲内の任意の値を取得するために使用する数式は、VLOOKUPでした。
検証結果シートへキャラクタースキルマスタIDを入力、tmp_検証用マスタからキャラクタースキルマスタIDが一致するキャラクタースキルの名前と検証結果を取得する数式を作ります。
またVLOOKUPでは値が見つからなかった場合にはエラーを返すため、その判定にIFERRORを使用しました。
ここでは両方の数式でキャラクタースキルIDを指定していますので、エラーメッセージは両方とも**キャラクタースキルIDが見つからない**という内容のものになります。

**キャラクタースキル名の取得**
1.IF数式を日本語で記述する
`=IFERROR({キャラクタースキル名の取得},{キャラクタースキルIDが見つからない場合のエラーメッセージ}`

2.日本語部分を数式で置き換える
VLOOKUPではB列を先頭として、キャラクタースキル名はC列のため、3番目の引数に2を指定
`=IFERROR(VLOOKUP(B3, 'tmp_検証用マスタ'!B4:I, 2, false), "NG: 指定したキャラクタースキルIDが見つかりません。[キャラクタースキルID:"&B3&"]")`

**検証結果の取得**
1.IF数式を日本語で記述する
`=IFERROR({検証結果の取得},{キャラクタースキルIDが見つからない場合のエラーメッセージ}`

2.日本語部分を数式で置き換える
VLOOKUPではB列を先頭として、検証結果はI列のため、3番目の引数に8を指定
`=IFERROR(VLOOKUP(B3, 'tmp_検証用マスタ'!B4:I, 8, false), "NG: 指定したキャラクタースキルIDが見つかりません。[キャラクタースキルID:"&B3&"]")`

上記のような数式になります。

キャラクタースキル名の取得で作成した数式を検証結果シートのC3に入力してC7までオートフィル、検証結果の取得で作成した数式を検証結果シートのD3に入力しD7までオートフィルします。
まだ、検証対象のキャラクタースキルIDを入力していないため、エラーメッセージが表示されていますが、この動作で正しいので問題ありません。
<img width="800" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/a637aeb4-775b-c7f9-e16e-f27ef5d714ca.png">

次にB3:B6までのセルに、1~4までを入力します。
下記の画像のように表示されたでしょうか。

<img width="800" alt="検証用テンプレ" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/423369/4881e38f-ae37-48d4-2255-92a72eeab7ba.png">

これで全ての要件を満たす実装を行うことができました。
実装についてはこれで全て終わりです。
お疲れ様でした。

#まとめ
今回は「Google スプレッドシートを使って文章を検証しよう」という内容で具体例を交えながら実装を行なってきました。数値を比較する検証であれば経験されている方が多いと思います。文章を使った検証はあまり見かけないため今回取り扱ってみましたがいかがでしたでしょうか。

正規表現はその表記の癖が強いため、もしかしたらとっつきにくい印象があるかもしれませんが、実際に覚えなくてはいけない表現はそんなに多くはありません。
少しの正規表現を使えるようになるだけで、検証の幅が大きく広がりますのでぜひこの機会にお試しください。

また今回は文章の検証に焦点を当てて説明を行ったため、オートフィルを使用しましたがオートフィルを使わずに同等の機能を作る数式もあります。実務で使用する際には[ARRAYFORMULA](https://support.google.com/docs/answer/3093275?hl=ja)と呼ばれる数式を使用した方が後々の運用やメンテナンスが楽になりますので、こちらも合わせて使ってみてください。

それでは、また来年もGoogle スプレッドシートを使用したエンジニアリングでお会いしましょう。