正規表現

 投稿者:しばっち  投稿日:2020年 8月26日(水)20時44分23秒
  C++ライブラリーを使用して十進BASIC上で正規表現が使えるようになりました。
今回はC++標準ライブラリーのみなので下記のcppソースだけでコンパイル可能です。

https://ja.wikipedia.org/wiki/正規表現
https://murashun.jp/blog/20190215-01.html
https://userweb.mnet.ne.jp/nakama/

サンプル
https://hodade.com/seiki/page.php?chapter_3
https://www.megasoft.co.jp/mifes/seiki/index.html

オンラインテスト
https://regex101.com/


検索文字列がはっきりしている場合は、対象が "ABCDE" なら十進BASICにあるPOS("ABCDE",A$)のようにPOS文で
検索できますが、3桁の数字に"-"(ハイフン)そして4桁の数字といった検索では少しやっかいです。
これは郵便番号を表すものですが、正規表現では "\d{3}-\d{4}" とすれば検索できます。("\d\d\d-\d\d\d\d"としても同じです)

但し、これでは電話番号の一部も検索対象になってしまいます。
郵便番号の後が半角スペースなら "\d{3}-\d{4} " とすればいいのですが
行末にある場合には対象になりません。この場合は正規表現のor表現を使って
"\d{3}-\d{4}( |$)" とすれば郵便番号の後が半角スペースか行末でも検索できるようになります。


使いこなすには慣れが必要ですが、正規表現を使えばこのような検索ができるようになります。




以下のプログラムは該当するファイル名を表示します。

OPTION CHARACTER BYTE
LET PATTERN$="^[A-E]" !'先頭文字がA~E
!'LET PATTERN$="[0-9]$" !'行末文字が数字
DIRECTORY GETNAME F$
LET F$=F$&"\*.*"
LET K=FILES(F$)
IF K>0 THEN
   DIM N$(K)
   FILE LIST F$,N$
ELSE
   STOP
END IF
FOR I=1 TO K
   FILE SPLITNAME(N$(I)) PATH$,NAME$,EXT$
   LET L=SEARCH_POS(PATTERN$,NAME$) !'部分一致
   !'LET L=SEARCH_LEN(PATTERN$,NAME$) !'部分一致
   !'LET L=MATCH(PATTERN$,NAME$) !'完全一致
   IF L>0 THEN
      PRINT NAME$;EXT$
   ELSEIF L=-9999 THEN
      PRINT "ERROR"
      STOP
   END IF
NEXT I
END

EXTERNAL  FUNCTION SEARCH_POS(PATTERN$,S$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\regex.dll","search_pos"
END FUNCTION

EXTERNAL  FUNCTION SEARCH_LEN(PATTERN$,S$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\regex.dll","search_len"
END FUNCTION

EXTERNAL  SUB SEARCH_STR(PATTERN$,S$,RESULT$)
OPTION CHARACTER BYTE
LET RES$=REPEAT$(CHR$(0),LEN(S$)+100)
LET L=SEARCH_STR_(PATTERN$,S$,RES$)
IF L>0 THEN
   FOR I=1 TO LEN(RES$)
      IF RES$(I:I)=CHR$(0) THEN EXIT FOR
   NEXT I
   LET RESULT$=RES$(1:I-1)
ELSE
   LET RESULT$=""
END IF

FUNCTION SEARCH_STR_(PATTERN$,S$,RES$)
   ASSIGN ".\DLL\regex.dll","search_str"
END FUNCTION
END SUB

EXTERNAL  SUB SEARCHES_POS(PATTERN$,SS$,P,OUT$)
OPTION CHARACTER BYTE
LET RET$=REPEAT$(CHR$(0),LEN(SS$))
LET P=SEARCHES_POS_(PATTERN$,SS$,RET$)
FOR I=1 TO LEN(RET$)
   IF RET$(I:I)=CHR$(0) THEN EXIT FOR
NEXT I
LET OUT$=RET$(1:I-1)

FUNCTION SEARCHES_POS_(PATTERN$,S$,OUT$)
   ASSIGN ".\DLL\regex.dll","searches_pos"
END FUNCTION
END SUB

EXTERNAL  SUB SEARCHES_LEN(PATTERN$,SS$,L,OUT$)
OPTION CHARACTER BYTE
LET RET$=REPEAT$(CHR$(0),LEN(SS$))
LET L=SEARCHES_LEN_(PATTERN$,SS$,RET$)
FOR I=1 TO LEN(RET$)
   IF RET$(I:I)=CHR$(0) THEN EXIT FOR
NEXT I
LET OUT$=RET$(1:I-1)

FUNCTION SEARCHES_LEN_(PATTERN$,S$,OUT$)
   ASSIGN ".\DLL\regex.dll","searches_len"
END FUNCTION
END SUB

EXTERNAL  SUB SEARCHES_STR(PATTERN$,S$,OUT$,RESULT$)
OPTION CHARACTER BYTE
LET RES$=REPEAT$(CHR$(0),LEN(S$)+100)
LET T$=REPEAT$(CHR$(0),LEN(S$))
LET L=SEARCHES_STR_(PATTERN$,S$,T$,RES$)
IF L>0 THEN
   FOR I=1 TO LEN(RES$)
      IF RES$(I:I)=CHR$(0) THEN EXIT FOR
   NEXT I
   LET RESULT$=RES$(1:I-1)
ELSE
   LET RESULT$=""
END IF
FOR I=1 TO LEN(T$)
   IF T$(I:I)=CHR$(0) THEN EXIT FOR
NEXT I
LET OUT$=T$(1:I-1)

FUNCTION SEARCHES_STR_(PATTERN$,S$,T$,RES$)
   ASSIGN ".\DLL\regex.dll","searches_str"
END FUNCTION
END SUB

EXTERNAL  FUNCTION MATCH(PATTERN$,S$)
OPTION CHARACTER BYTE
ASSIGN ".\DLL\regex.dll","match"
END FUNCTION

EXTERNAL  FUNCTION REPLACE$(PATTERN$,S$,REP$)
OPTION CHARACTER BYTE
LET RESULT$=REPEAT$(CHR$(0),LEN(S$)+500)
IF REPLACE_(PATTERN$,S$,REP$,RESULT$)=1 THEN
   FOR I=1 TO LEN(RESULT$)
      IF RESULT$(I:I)=CHR$(0) THEN EXIT FOR
   NEXT I
   LET REPLACE$=RESULT$(1:I-1)
ELSE
   LET REPLACE$=""
END IF

FUNCTION REPLACE_(PATTERN$,S$,REP$,RESULT$)
   ASSIGN ".\DLL\regex.dll","replace"
END FUNCTION
END FUNCTION
--------------------------------------------------------------------
                              regex.cpp

#include <regex>
#include <string>

using namespace std;

extern "C"  __declspec(dllexport) int search_pos(char *pattern,char *ss)
{
    smatch match;
    string str=ss;

    try {
        if (regex_search(str, match, regex(pattern)))
            return match.position(0)+1;
        else return 0;
    } catch(...) {
        return -9999;
    }
}

extern "C"  __declspec(dllexport) int search_len(char *pattern,char *ss)
{
    smatch match;
    string str=ss;

    try {
        if (regex_search(str, match, regex(pattern)))
            return match.length(0);
        else return 0;
    } catch(...) {
        return -9999;
    }
}

extern "C"  __declspec(dllexport) int search_str(char *pattern,char *ss,char *result)
{
    smatch match;
    string str=ss,tt;

    try {
        if (regex_search(str, match, regex(pattern)))
        {
            tt=match[0].str();
            strcpy(result,tt.c_str());
            return 1;
        }
        else return 0;
    } catch(...) {
        return -9999;
    }
}

extern "C"  __declspec(dllexport) int searches_pos(char *pattern,char *ss,char *out)
{
    smatch match;
    string str=ss;
    int pos;

    try {
        if (regex_search(str, match, regex(pattern)))
        {
            pos=match.position(0)+1;
            str=match.suffix();
            strcpy(out,str.c_str());
            return pos;
        }
        else return 0;
    } catch(...) {
        return -9999;
    }
}

extern "C"  __declspec(dllexport) int searches_len(char *pattern,char *ss,char *out)
{
    smatch match;
    string str=ss;
    int len;

    try {
        if (regex_search(str, match, regex(pattern)))
        {
            len=match.length(0);
            str=match.suffix();
            strcpy(out,str.c_str());
            return len;
        }
        else return 0;
    } catch(...) {
        return -9999;
    }
}

extern "C"  __declspec(dllexport) int searches_str(char *pattern,char *ss,char *out,char *result)
{
    smatch match;
    string str=ss,tt;

    try {
        if (regex_search(str, match, regex(pattern)))
        {
            tt=match[0].str();
            strcpy(result,tt.c_str());
            str=match.suffix();
            strcpy(out,str.c_str());
            return 1;
        }
        else return 0;
    } catch(...) {
        return -9999;
    }
}

extern "C"  __declspec(dllexport) int match(char *pattern,char *ss)
{
    smatch match;
    string str=ss;

    try {
        if (regex_match(str, match, regex(pattern)))
            return match.length(0);
        else return 0;
    } catch(...) {
        return -9999;
    }
}

extern "C"  __declspec(dllexport) int replace(char *pattern,char *ss,char *rep,char *result)
{
    string str=ss,r;

    try {
        r=regex_replace(str, regex(pattern),rep);
        strcpy(result,r.c_str());
        return 1;
    } catch(...) {
        return -9999;
    }
}



下記はテキストファイルを読み込み該当するデータを抽出し表示します。

FILE GETNAME F$
IF F$="" THEN STOP
OPEN #1:NAME F$
DO
   LINE INPUT #1,IF MISSING THEN EXIT DO:A$
   IF A$<>"" THEN
   !  LET P=SEARCH_POS("\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",A$) !'Email アドレス
   !  LET L=SEARCH_LEN("\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",A$) !'Email アドレス
   !  IF P>0 THEN
   !     PRINT A$(P:P+L-1)
   !  END IF

      LET R$=SEARCH_STR$("\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",A$) !'Email アドレス
      IF R$<>"" THEN PRINT R$

      LET R$=SEARCH_STR$("(https|http)?://([\w-]+\.)+[\w-]+(/[\w-./?%&=]*)?",A$) !'URL
      IF R$<>"" THEN PRINT R$

      LET R$=SEARCH_STR$("0\d(-\d{4}|\d-\d{3}|\d\d-\d\d|\d{3}-\d)-\d{4}",A$) !'固定電話
      IF R$<>"" THEN PRINT R$

      LET R$=SEARCH_STR$("0[789]0-\d{4}-\d{4}",A$) !'携帯電話
      IF R$<>"" THEN PRINT R$

      LET R$=SEARCH_STR$("(0120|0800)-\d{3}-\d{3}",A$) !'フリーダイヤル
      IF R$<>"" THEN PRINT R$

      LET R$=SEARCH_STR$("\d{4}.\d\d.\d\d",A$) !'日付 (YYYY-MM-DD形式)
      IF R$<>"" THEN PRINT R$

      LET R$=SEARCH_STR$("\d{3}-\d{4}",A$) !'郵便番号
      IF R$<>"" THEN PRINT R$

   END IF
LOOP
CLOSE #1
END

同一行内に検索対象が複数個所ある場合はループを使用して処理します。
dll内で行うには都合が悪かったのでBASIC側にてループで処理します。

LET A$="abcdef    Abc    1230abcde   abc "
DO
   CALL SEARCHES_STR("( |^)[a-z]+",A$,OUT$,RESULT$)
   IF RESULT$="" THEN EXIT DO
   PRINT RESULT$
   LET A$=OUT$
LOOP
PRINT "---------------------------------------"
LET A$="abcdef    Abc    1230abcde   abc "
DO
   CALL SEARCHES_POS("( |^)[a-z]+",A$,P,OUT$)
   IF P=0 THEN EXIT DO
   CALL SEARCHES_LEN("( |^)[a-z]+",A$,L,OUT$)
   PRINT A$(P:P+L-1)
   LET A$=OUT$
LOOP
END


VC++2019にてコンパイルしました。(regex.zip)
下記よりダウンロードしてください。

https://16.gigafile.nu/0925-d0a767ca924f6da0c68d30eba2537358d


ダウンロードパス:設定していません
ダウンロード期限:2020年9月25日(金)
 

戻る