|
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日(金)
|
|