同じ文字や文字列の繰り返しを判定・抽出する

 文字列中にある同じ文字や文字列の繰り返しを検出したり抽出したりする方法についてです。
 文字の種類だけでも膨大な数になり、さらに2文字以上の文字列まで判定の対象に含めると「ああ」「あああ」などと一つ一つ指定していくのはとても現実的ではありません。
 そこで正規表現(RegExpオブジェクト)を用いて解決してみます。

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

 このようなテーブルがあります。
 「文字列」列に記録されている文字列から、同じ文字や文字列が2回以上繰り返されている部分をすべて抽出してみます。

f:id:accs2014:20191103163133p:plain:right:w450

 早速ですが標準モジュールに次のようにユーザ定義関数を記述します。

Option Compare Database

Function reg_reptstring(arg As Variant) As Variant

    Dim reg_exp As Object
    Set reg_exp = CreateObject("VBScript.RegExp")

    With reg_exp
        .Global = True       '文字列全体を対象とする
        .IgnoreCase = False  '大文字と小文字を区別する
        .Pattern = "(.+)\1+" 'マッチング対象を表すパターン
    End With

    Dim reg_matches As Object, i As Object
    Dim txt As Variant
     
    If IsNull(arg) = False Then
        Set reg_matches = reg_exp.Execute(arg)
        
        For Each i In reg_matches
            txt = txt & i.Value & ","
        Next

        If Len(txt) > 0 Then
            reg_reptstring = Left(txt, Len(txt) - 1)
        End If
    End If
    
    Set reg_exp = Nothing

End Function

※¥がバックスラッシュとして表示されているかもしれません。

 RegExpオブジェクト自体については本編記事(RegExpオブジェクトの機能)を参照願います。
 肝となるのはPatternプロパティに設定している正規表現「(.+)¥1+」であり、これだけで様々な長さの文字列が2回以上繰り返されていることを表現し、検出することができます。
 簡単に言って「(.+)」は1文字以上の文字列を、「¥1+」は「(.+)」によりマッチした文字列の内容と同じものが1回以上現れることを、それぞれ示しています。これらを総合すると「1文字以上の文字列が2回以上繰り返されている」部分にマッチすることとなります。
 For Each文以降の処理により、繰り返す文字列が複数ある場合は、それらをカンマでつないで返します。

f:id:accs2014:20191103165537p:plain:right:w500

 クエリデザインに上記テーブルを置き、次の式を設けます。

繰り返し部分: reg_reptstring([文字列])

f:id:accs2014:20191103165541p:plain:right:w600

 デザインビューです。
 1行目ですが「は」や「こん」のように複数回出現する文字列がありますが、繰り返しにはなっていないので抽出されません。
 2行目では「こ」が2回繰り返されている「ここ」という部分が抽出されています。
 3行目は3文字×3回の繰り返しを抽出しています。3回以上の繰り返しもすべて抽出されます。
 4行目では助詞の繰り返し「をを」を抽出しています。こうした抽出は校正の際にも有効と考えられます。
 5行目では4か所の繰り返し部分があり、それらがカンマでつないで表示されています。
 6行目では「ドドンパ」は2回続いているため抽出されていますが、「ドド」が別途抽出されていないことに注意してください。このパターンでは、大きな繰り返し部分に含まれる小さな繰り返し部分は抽出されません。