いきなり答える備忘録

Google Workspace(旧G Suite)・Microsoft 365・LibreOfficeなどに関するメモ

(Gスプレッドシート)正規表現の基本的な使い方まとめ

 Googleスプレッドシートでは正規表現を用いた文字列の検索や操作を行うことが可能です。
 正規表現は簡単に言えばワイルドカードの強力版のようなもので、やや複雑ですが高度な文字列操作ができます。
 以下では正規表現の概要といくつかの使用例を紹介します。

  • Googleスプレッドシートでは一部の関数やメニューで正規表現を使用することができ、ワイルドカードによるものと比べて高度な文字列の検索・操作が可能です。

手順

正規表現とは

 正規表現は通常の文字(リテラル)と特別な意味を持った各種の記号(メタキャラクタ)を組み合わせて、文字列の特徴を表現するものです。簡単な例だと「A..」という正規表現は「『A』で始まる3文字」を表します。つまり「ABC」や「ANT」などがこの正規表現に該当(マッチ)します。
 考え方としてはワイルドカードと同様ですが、正規表現では様々なメタキャラクタが用意されており、複雑な特徴をもつ文字列を比較的単純なパターンで表現することができます。
 スプレッドシートでは「検索と置換」メニューで正規表現を使った文字列検索と置換ができるほか、正規表現を使って検索・抽出・置換ができる関数が用意されており、従来のLEFT,RIGHT,MIDといった関数よりも柔軟で高度な文字列操作が可能となっています。

正規表現の使用例

 正規表現の詳しい内容より先に、正規表現がどこでどのように使えるのかを簡単にみてみます。

「検索と置換」メニューでの使用例

 メニューを使ってシート上の半角数字を特定の文字に置き換える例をみてみます。
 メニューから「編集」→「検索と置換」と進み(またはCtrl+H)、ダイアログを出現させます。
 ここで検索欄に「[0-9]」と入力し、置換後の文字列欄に「x」と入力します。さらに「正規表現を使用した検索」にチェックを入れます。
 「[0-9]」というのは正規表現で「0から9までの半角数字」を表します。これらをすべて「x」に置き換えよう、というわけです。

f:id:accs2014:20201220132420p:plain:w700

 
 「すべて置換」をクリックすると、すべての半角数字が「x」に置き換えられました。
 B5セルに数値として入力されていた5桁の数字も、文字列に変更されているのがわかります。
 余談ですが対象が「すべてのシート」になっている(デフォルト)ため他のシートの半角数字も置き換えられ、置換箇所数が22個となっています。必要以上に置き換えてしまわないよう注意が必要です。

f:id:accs2014:20201220132424p:plain:w700

関数での使用例

 Googleスプレッドシートでは4つの関数で正規表現を利用することができます。

f:id:accs2014:20201220132428p:plain:right:w550

 各関数については改めて紹介しますが、ここではREGEXREPLACE関数(正規表現にマッチする部分を置き換える関数)を使い、上記の例と同様の置換を行っています。
 D3セルに次のような式を入力し、下方にコピーしています。

 D3セル

=REGEXREPLACE(B3,"[0-9]","x")

 第1引数は文字列全体、第2引数は置換対象を表す正規表現(この場合は半角数字にマッチ)、第3引数は置換後の文字列です。
 複数の置換対象を一括して指定できるため、SUBSTITUTE関数などを用いるよりスマートに処理できるのが特徴です。
 ただし、上記のメニューでの使用例と異なり、D5セルのように第1引数が文字列でない場合にはエラーが返る点に注意が必要です。

メタキャラクタ

 ここでは正規表現を構成するメタキャラクタについてみてみます。これらを組み合わせることでさまざまな種類・長さの文字列を指定できます。
 ただしここで紹介するのはGoogleスプレッドシートで使えるメタキャラクタのすべてではなく、省略しているものもあります。

文字を表すメタキャラクタ

 任意の文字、または特定の種類の文字を表すメタキャラクタです。複数種の文字をまとめて1つの文字として表すことができ、何種類もの文字を1つ1つ列挙することなく表現できます。
 ここでは「~のいずれか」や「~以外」を表す表現も含めて紹介します。

記号意味
.任意の1文字
[abc](abcはリテラル)
列挙した文字のうちいずれか1文字
[a-z](aとzはリテラル)
指定した範囲のうちいずれか1文字
数字やひらがな、カタカナ等も同様に範囲指定ができます
abc|def(abcとdefはリテラル)
指定した文字列(この場合abcかdef)のうちいずれか
[^abc](abcはリテラル)
列挙した文字以外の1文字
\w半角英字(a~zとA~Z),半角数字(0~9),アンダースコア(_)のいずれか1文字
\W半角英字(a~zとA~Z)、半角数字(0~9)、アンダースコア(_)以外の1文字
\d半角数字(0~9)のいずれか1文字
\D半角数字(0~9)以外の1文字
\n改行

 これらは繰り返して使うことができますし、組み合わせて使うこともできます。
 例えば「...」と並べれば任意の3文字にマッチしますし、「[ABC]D」とすれば「AD」のほか「BD」「CD」にマッチします。
 また、次に紹介する繰り返しを表すメタキャラクタを使えば、より複雑な繰り返しの表現が可能です。

長さ(繰り返し)を表すメタキャラクタ

 文字の長さ(繰り返し)を表現するメタキャラクタで、上記の文字を表すメタキャラクタと組み合わせて使います。
 量指定子とも呼ばれます。

記号意味
*0回以上の繰り返し(なるべく長くマッチ)
+1回以上の繰り返し(なるべく長くマッチ)
?0回か1回の繰り返し(0回より1回にマッチ)
{n}n回の繰り返し
{n,}n回以上の繰り返し(なるべく長くマッチ)
{n,m}n回以上m回以下の繰り返し(なるべく長くマッチ)

 例えば「A+」という正規表現は、「A」のほか「AA」や「AAA」などにマッチします。より長い部分にマッチしますので、文字列「AAAAA」に対して正規表現「A+」はその全体、つまり「AAAAA」にマッチします。
 ただし、関数の機能などとの兼ね合いもあり、実際に文字列中のどの部分が処理の対象となるのかについては注意する必要があります。
 例としてREGEXEXTRACT関数を使った2つの式の例を見てみます。

式① :=REGEXEXTRACT("BAAAC","A+")
結果①:AAA
式② :=REGEXEXTRACT("BAAACAAAAA","A+")
結果②:AAA

 「A+」という正規表現は、連続する「A」の字に対してできる限り長くマッチしようとしますので、式①の結果は「AAA」となります。では式②の結果が「AAAAA」となるかといえばそうではなく、これも「AAA」を返します。なぜかというとREGEXEXTRACT関数は基本的に最初にマッチしたものしか返さないからです。どれだけAの字が長く続く部分があっても、最初に続いているAが途切れた時点でそれ以降は抽出の対象となりません。
 正規表現を活用するためには量指定子に対する理解が欠かせませんが、さらに関数などの機能についても正確に把握する必要があります。

 また、2文字以上の文字列の繰り返しを指定する場合、文字列をカッコで囲みます。例えば「(ABC)+」は「ABC」のほか「ABCABC」「ABCABCABC」などにマッチします(下記でも紹介しているグループ化の効果です。ただしREGEXEXTRACT関数のようにグループ化が別の効果をもたらす場合もあるので注意が必要です)。

 なお、「?」と他のメタキャラクタを組み合わせて次のような表現も可能です。
 これらの表現の意味を正確に判断して使い方を見出すのは慣れても難しいところですが、参考まで。

記号意味
*?0回以上の繰り返し(なるべく短くマッチ)
+?1回以上の繰り返し(なるべく短くマッチ)
??0回か1回の繰り返し(1回より0回にマッチ)
{n}?n回の繰り返し
({n}と同じ)
{n,}?n回以上の繰り返し(なるべく短くマッチ)
{n,m}?n回以上m回以下の繰り返し(なるべく短くマッチ)

特定の位置を表すメタキャラクタ

記号意味
^文字列の先頭
$文字列の末尾
\b上記の「\w」に該当する文字、つまり半角英字(a~zとA~Z),半角数字(0~9),アンダースコア(_)が1文字以上連なっているときの、その前後の位置
\B「\w」に該当する文字、つまり半角英字(a~zとA~Z),半角数字(0~9),アンダースコア(_)以外の文字が1文字以上連なっているときの、その前後の位置

 頻繁に使うのは「^」と「$」です。このうち「^」は「[^0-9]」(半角数字以外)のような例でも出てきますが、ここでは別の意味ですので注意が必要です。
 「^」は文字列の先頭を指し「$」は文字列の末尾を表します。「~のうち最初にあるもの」とか「~のうち最後にあるもの」といったように検索の優先順位を表すのではなく、「先頭」と「末尾」そのものを指しています。
 どういうことかわかりにくいので、REGEXREPLACE関数を使った次の例を見てみます。

式 :=REGEXREPLACE("こんにちは","^","☆")
結果:☆こんにちは

 「こんにちは」という文字列の先頭を「☆」に置き換えた結果、「☆んにちは」ではなく「☆こんにちは」になります。「先頭の文字(こ)」ではなく、先頭そのものを置き換えるからです。
 ただ、実際の用途としては先頭や末尾にある文字を操作するために用いられる場合がほとんどです、「^こん」という正規表現は文字列の先頭にある「こん」にマッチしますし、「ちは$」は文字列の末尾にある「ちは」にマッチします。

グループ化

記号意味
(abc)(abcはリテラル)
2文字以上の文字を、量指定子による繰り返しの対象にすることができます
関数等によっては別の効果を得ることができ、特にREGEXEXTRACT関数やREGEXREPLACE関数などで有効です(キャプチャグループ)
(?:abc)(abcはリテラル)
2文字以上の文字を、量指定子による繰り返しの対象にすることができます
関数等によって得られる別の効果を免れることができます(非キャプチャグループ)

 例えば「(ABC)+D」という正規表現は「ABCD」「ABCABCD」などにマッチします。
 また、上記で紹介した「-」や「|」などとの併用ももちろん可能です。例えば「(ABC|DEF)+G」は「ABCG」「ABCABCG」「DEFG」「DEFDEFG」などにマッチします。
 キャプチャの部分はなかなかわかりにくいですが、関数の紹介記事にて例を示します。

正規表現を使える4つの関数

REGEXMATCH関数

 文字列中に正規表現にマッチする部分が1つでもあればTRUEを返し、1つもなければFALSEを返す関数です。
 式と結果の例は次のようになります。

式 :=REGEXMATCH("福島県","^福")
結果:TRUE

 「^福」という正規表現は文字列の先頭にある「福」の字を表します。一方で「福島県」は「福」の字で始まっていますので、結果はTRUEとなります。
 文字列がワイルドカード(*や?を使ったもの)とマッチするかどうかを直接判定する関数はありません(そこでCOUNTIF関数が代用されます)。しかし正規表現についてはREGEXMATCH関数により直接判定することができるというのがポイントです。
 使用頻度は高くないかもしれませんが、FILTER関数と組み合わせて「~を含む」などの抽出条件を設けるのが代表的な利用法です。

REGEXEXTRACT関数

 文字列中の、正規表現にマッチする部分を抽出して返します。マッチする部分が複数ある場合、基本的に最初にマッチした1つの部分しか返しません
 以下は式と結果の例です。

式 :=REGEXEXTRACT("島根県-福島県-福井県","福..")
結果:福島県

 「福..」という正規表現は「福」で始まる3文字にマッチします。文字列中では「福島県」と「福井県」の2か所がマッチしますが、REGEXEXTRACT関数は最初にマッチした1つを抽出するので結果は「福島県」となります。

 なお、こちらの記事でさらにいくつかの使用例を紹介しています。

www.officeisyours.com


REGEXREPLACE関数

 文字列中の、正規表現にマッチする部分を別の文字列に置き換えます。マッチする部分が複数ある場合、マッチする部分をすべて置き換えます
 式と結果の例は次のとおりです。

式 :=REGEXREPLACE("島根県-福島県-福井県","福..","☆")
結果:島根県-☆-☆

 「福..」という正規表現は、文字列中の「福島県」と「福井県」の2か所がマッチします。REGEXREPALCE関数はマッチした部分をすべて置き換えるので、結果は「島根県-☆-☆」となります。

QUERY関数

 QUERY関数は表からのデータの抽出や並べ替え等を一括して行うことができる重要な関数です。
 この関数でも正規関数を利用することができ、正規表現に該当する行を抽出することができます。具体的には第2引数(クエリ文字列)内に「WHERE ~ MATCHES '正規表現'」という句を設けることで条件を指定することができます。
 以下は式の例です。

=QUERY(B2:C10,"WHERE B MATCHES '福..'",1)

 これはB,C列に記録された表のうち、「B列の値が『福』で始まる3文字」である行を抽出するというものです。他の関数では文字列中の一部がマッチすれば処理の対象となりますが、QUERY関数では一部がマッチするだけでは抽出せず、文字列全体が正規表現に一致しないと抽出しません
 なお、マッチしない行を抽出する場合は「WHERE NOT ~ MATCHES '正規表現'」とします。この場合は次のようになります。

=QUERY(B2:C10,"WHERE NOT B MATCHES '福..'",1)

おわりに

 文字列操作用の関数というとLEFT,RIGHT,MIDといったものが挙げられます。しかしその多くは「何文字目」という文字位置や長さを数値により指定する必要があるので、実用的にはFIND関数などと併用する必要があり、式が複雑になったり長くなる傾向があります。
 しかし正規表現に関しては基本的にこれらを考慮する必要がなく、操作したい文字列を表現できれば直接操作の対象とすることができます。
 もちろん欠点もあります。機能が多彩な分、マッチさせようとする文字列を正確に表現するのは難しく、特に次のような点が困難です。

  • AND,OR,NOTの判定を組み込むことが難しい
  • 量指定子の効果が複雑でわかりにくい。さらに関数によって操作の対象が異なること理解の妨げになる
  • グループ化の効果がわかりにくく、特にREGEXEXTRACT関数では意図しない結果をもたらしやすい
 それでも効果は絶大で、簡単に理解できる部分だけでも大きな成果を得ることができますので、ぜひ試していただきたいと思います。