Bregexp ライブラリ 1.0

1999.11.25 更新

Bregexp ライブラリは、正規表現(Regular Expression)関数を提供します。 あなたのアプリケーションにPerl5互換の正規表現パワーが欲しい方是非どうぞ。
Red Hat Linux 6.1 gccコンパイラ以外での動作確認を行っておりません。 他のプラットホームで動かしてみた方、お知らせくださればありがたいです。
bregexp-1.0.tgz (40KB) Down Load!
MD5 チェックサム: cb2d54ed0ed247df220a5ab027e1a405

インストール

ダウンロードした bregexp-1.0.tgz を適当なディレクトリにコピーします。
C++ソース提供ですので gcc などのC++コンパイラがないとインストールできません。
RedHat 以外の LinuxやUNIX では Makefile ファイルを環境に合わせて変更して みてください。
次のような手順でインストールします。

$ tar zxvf bregexp-1.0.tgz           解凍します
                                     tar の z オプションがエラーなら
                                     $ gunzip bregexp-1.0.tgz
                                     $ tar xvf bregexp-1.0.tar
$ ls
bregexp-1.0  bregexp-1.0.tgz
$ cd bregexp-1.0                     ディレクトリを変更して
$ make                               コンパイル、ライブラリを作成します
$ su                                 エラーが出なかったら root ユーザになります

# make install                       /usr/include に bregexp.h
                                     /usr/lib にライブラリがコピーされます
# exit
$ ls /usr/include/bre*              ファイル名を確認します
/usr/include/bregexp.h       ....... ヘッダーファイル         
$ ls /usr/lib/libbre*
/usr/lib/libbregexp.a        ....... スタティックライブラリ
/usr/lib/libbregexp.so.1.0   ....... 共有ライブラリ
/usr/lib/libbregexp.so.1     ....... 共有ライブラリへのリンク
/usr/lib/libbregexp.so       ....... 共有ライブラリへのリンク

$ gcc sample.c -lbregexp             サンプルプログラムをコンパイルできれば OK
$ ./a.out /home/                     ちょっと実行

ライブラリの基礎知識

Linux では、ライブラリには次の3種類あります。 スタティックライブラリは、コンパイル時にコードがプログラムに組込まれます。 モジュールサイズが大きくなりますが、別のマシンにバイナリで配布したときに そのライブラリがなくても動作します。
共有ライブラリは、プログラムの実行時にロードされます。マシンによっては、 その共有ライブラリがなかったり、バージョンが違ったりして、動作しないことがあります。
ダイナミックライブラリは、共有ライブラリの1種です。実行時に 関数を使って ロードしたり、アンロードしたりできます。
ダイナミックライブラリは、位置に依存しないコードですので gcc で -fPIC オプション をつけてコンパイルします。 この辺の説明は、 ELF HOWTOをみましょう。

$ gcc -fPIC -c xxx.c
$ gcc -shared -Wl,-soname,libxxx.so.1 -o libxxx.so.1.0 xxx.o

スタティックライブラリは、ar コマンドで作成します。

$ ar rv libxxx.a xxx.o
$ ranlib libxxx.a

Bregexp ライブラリは、RedHat Linux 上ではスタティックライブラリ、共有(ダイナミック)ライブラリの 2つを提供しています。
スタティックライブラリを使う場合は、次のようにリンクします。
$ gcc sample.c -o sample /usr/lib/libbregexp.a
共有ライブラリを使う場合は、次のようにリンクします。
$ gcc sample.c -o sample -lbregexp

プログラムがどんな共有ライブラリを使っているか調べるには ldd コマンドというのが あります。
$ ldd sample
        libbregexp.so.1 => /usr/lib/libbregexp.so.1 (0x40016000)
        libc.so.6 => /lib/libc.so.6 (0x4002c000)
        /lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)


他のUNIX環境では、共有ライブラリの作成方法がそれぞれ異なっているようです。

Bregexp ライブラリが提供する関数一覧

パターンについて

正規表現は、文字列をパターンとして処理します。 パターンは、次のように"/"で囲んで指定します。
/パターン/修飾子
パターン文字に"/"を含む場合は、次のようにmを指定して別の文字を使うことができます。
m#パターン#修飾子
パターンの中にはメタ文字という特別の意味を持つ文字があります。 このメタ文字をマスターすると正規表現のパワーを実感できます。 Bregexp ライブラリで使えるメタ文字とその意味は、Perl5とほぼ同じです。従ってPerl5での 正規表現をそのままBregexp ライブラリのパターンとして使えます。 次にBregexp ライブラリで使えるメタ文字を示します。
         \     次のメタ文字をクォートする(取り消す)
         ^     行の最初にマッチする
         .     (改行以外の) すべての文字にマッチする
         $     行の終わりにマッチする
         |     選択
         ()    グループ化
         []    文字クラス

         \w   単語」の構成文字 (英数字と "_") にマッチ
         \W    単語の構成文字以外にマッチ
         \s    空白文字にマッチ
         \S    空白文字以外にマッチ
         \d    数字にマッチ
         \D    数字以外にマッチ
         \b    単語の境界にマッチ
         \B    単語の境界以外にマッチ
         \A    文字列の最初にのみマッチ
         \Z    文字列の最後にのみマッチ
         \t    タブ
         \n    改行
         \r    復帰
         \f    改ページ
         \a    アラーム (ベル)
         \e    エスケープ
         \033  8 進数で表した文字
         \x1b  16 進数で表した文字
         \c[   コントロール文字
直前の文字の数量子:
         *      0 回以上にマッチ
         +      1 回以上にマッチ
         ?      1 回または 0 回にマッチ
         {n}    ちょうど n 回にマッチ
         {n,}   n 回以上にマッチ
         {n,m}  n 回以上 m 回以下にマッチ


修飾子は、つぎのようなものです。
         k   文字を日本語(SJIS)として扱う(Perlにはこの修飾子はありません)
         m   文字列を複数行として扱う(メタ文字$の処理結果に影響を及ぼします)
         g   置換:グローバルな置換
         c   変換:SEARCHLIST を補集合にする
         d   変換:見つかったが置換されなかった文字を削除する
         s   変換:置換された文字が重なったときに圧縮する
         

非互換について

次にような機能は、Bregexp ライブラリではサポートしていません。

●VBなどでパターンに変数名を書いても展開されません
●メタ文字
         \G    前回の m//g が終わったところにのみマッチ
●修飾子(パターンの右側につけるパラメータ)
         o     一度だけコンパイル
         x     拡張正規表現を使用する
         e     式の右側の評価を行なう

使い方

bregexp.h ヘッダーファイルをインクルードして関数を呼出します。 コンパイルは、次のようにします。
$ gcc sample.c -o sample -lbregexp
$ sample /home/
$ sample /\\d{4}/ xxxx.text

=================== sample.c 開始 ======================================
//
//  sample.c
//
// grep for bregexp version
//                     Author Tatsuo Baba
//
#include <stdio.h>
#include <bregexp.h>
int main(int argc,char *argv[])
{
    char fname[512],line[4096];
    char msg[80],*p1;
    FILE *fp;
    int len,ctr;
    BREGEXP *rxp = 0;
    char dmy[] = " ";
    if (argc < 2) {
        puts ("usage /regstr/ [file]\n  if omitted assume /usr/dict/words");
        return 0;
    }
    strcpy(fname,"/usr/dict/words");
    if (argc > 2)
        strcpy(fname,argv[2]);
    p1 = argv[1];
    fp = fopen(fname,"r");
    if (!fp) {
        printf ("file cant open  %s\n",fname);
        return 0;
    }
    BMatch(p1,dmy,dmy+1,&rxp,msg);  // compile using dummy
    if (msg[0]) {
        printf ("parse error  %s\n",msg);
        return 0;
    }
    ctr = 0;
    while(fgets(line,sizeof(line),fp)) {
        len = strlen(line);
        if (len && BMatch(p1,line,line+len,&rxp,msg)) {
            ctr++;
            line[len-1] = 0;
            puts(line);
        }
     }
     fclose(fp);

     printf("%ld lines(s) greped\n",ctr);
     return 0;
}
=================== sample.c 終了 ======================================

=================== bregexp.h 開始 ======================================

typedef struct bregexp {
	const char *outp;	// BSubst 置換データの先頭ポインタ
	const char *outendp;	// BSubst 置換データの最終ポインタ+1
	const int  splitctr;	// BSplit 配列数
	const char **splitp;	// BSplit データポインタ
	int	rsv1;		// リザーブ 自由に使用可能 
	char *parap;		// パターンデータポインタ
	char *paraendp;		// パターンデータポインタ+1
	char *transtblp;	// BTrans 変換テーブルポインタ
	char **startp;		// マッチしたデータの先頭ポインタ
	char **endp;		// マッチしたデータの最終ポインタ+1
	int nparens;		// パターンの中の() の数。 $1,$2, を調べるときに使用
} BREGEXP;



#if defined(__cplusplus)
extern "C"
{
#endif

int BMatch(char* str,char *target,char *targetendp,
                BREGEXP **rxp,char *msg) ;
int BSubst(char* str,char *target,char *targetendp,
                BREGEXP **rxp,char *msg) ;
int BTrans(char* str,char *target,char *targetendp,
                BREGEXP **rxp,char *msg) ;
int BSplit(char* str,char *target,char *targetendp,
                int limit,BREGEXP **rxp,char *msg);
void BRegfree(BREGEXP* rx);

char* BRegexpVersion(void);

#if defined(__cplusplus)
}
#endif


=================== bregexp.h 終り ======================================

BREGEXP構造体について

Bregexp ライブラリでは、パラメータとしてBREGEXP構造体を使います。 BREGEXP構造体は、コンパイルブロックとも呼びます。
BREGEXP構造体は: などの機能を持ちます。 BREGEXP構造体をうまく使うと処理を高速化できます。 同じ正規表現を使う関数の呼出しには、同じコンパイルブロックを使えばいいのです。

BMatch関数のサンプル

	char msg[80];	// メッセージ領域
	BREGEXP *rxp = NULL;	// 必ずクリアしておくこと 
	// 検索文字サンプル
	char t1[] = " Yokohama 045-222-1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 ";
	char patern1[] = "/(03|045)-(\\d{3,4})-(\\d{4})/";	// /(03|045)-(\d{3,4})-(\d{4})/
						// 03か045 の電話番号を検索
						// カッコ() は、それぞれの番号を記憶することを意味する
	int pos = 0;	// 検索ポジション
	while (BMatch(patern1,t1+pos,t1+lstrlen(t1),&rxp,msg)) {
		printf("data=%s\n",t1+pos);		// 検索される文字
		printf("found=%s\n",rxp->startp[0]);	// マッチ文字列
		printf("length=%d\n",rxp->endp[0] - rxp->startp[0]);	// マッチ文字数
		for (int i = 1;i <= rxp->nparens;i++) {		// カッコ内のデータ 
			printf("$%d = %s\n",i,rxp->startp[i]);
			printf("$%d length = %d\n",i,rxp->endp[i]-rxp->startp[i]);
		}
		pos = rxp->endp[0] - t1;		// 次の文字の検索位置
	}

	pos = 0;
	char t2[] = " abcdabce abcdabcd abcdabcf abcgabcg ";
	char patern2[] = "/abc(.)abc\\1/";	// 検索中でのパターン記憶の例
	while(BMatch(patern2,t2+pos,t2+lstrlen(t2),&rxp,msg)) {
		printf("data=%s\n",t2);			// 検索される文字
		printf("found=%s\n",rxp->startp[0]);	// マッチ文字列
		printf("length=%d\n",rxp->endp[0] - rxp->startp[0]);	// マッチ文字数
		for (int i = 1;i <= rxp->nparens;i++) {		// カッコ内のデータ 
			printf("$%d = %s\n",i,rxp->startp[i]);
			printf("$%d length = %d\n",i,rxp->endp[i]-rxp->startp[i]);
		}
		pos = rxp->endp[0] - t2;	// 次の文字の検索位置
	}

	if (rxp)			// コンパイルブロックの開放
		BRegfree(rxp);		// 忘れないように

結果:
data= Yokohama 045-222-1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 
found=045-222-1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 
length=12
$1 = 045-222-1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 
$1 length = 3
$2 = 222-1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 
$2 length = 3
$3 = 1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 
$3 length = 4
data=  Osaka 06-5555-6666  Tokyo 03-1111-9999 
found=03-1111-9999 
length=12
$1 = 03-1111-9999 
$1 length = 2
$2 = 1111-9999 
$2 length = 4
$3 = 9999 
$3 length = 4
data= abcdabce abcdabcd abcdabcf abcgabcg 
found=abcdabcd abcdabcf abcgabcg 
length=8
$1 = dabcd abcdabcf abcgabcg 
$1 length = 1
data= abcdabce abcdabcd abcdabcf abcgabcg 
found=abcgabcg 
length=8
$1 = gabcg 
$1 length = 1



BSubst関数のサンプル

2桁の市外局番の市内番号をxxxxに変更します。
	char msg[80];	// メッセージ領域
	BREGEXP *rxp = NULL;	// 必ずクリアしておくこと 
	// 置換文字サンプル
	char t1[] = " Yokohama 045-222-1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 ";
	char patern1[] = "s/(\\d\\d)-\\d{4}-\\d{4}/$1-xxxx-xxxx/g";
	int ctr;
	if (ctr = BSubst(patern1,t1,t1+lstrlen(t1),&rxp,msg)) {
		printf("after(%d)=%s\n",ctr,rxp->outp);	// 置換したパターン数と文字列
		printf("length=%d\n",rxp->outendp - rxp->outp);	// 置換後の文字数
	}

	if (rxp)			// コンパイルブロックの開放
		BRegfree(rxp);		// 忘れないように

結果:
after(2)= Yokohama 045-222-1111  Osaka 06-xxxx-xxxx  Tokyo 03-xxxx-xxxx 
length=63



BTrans関数のサンプル

大文字を小文字に、数字をxに変換します。

	char msg[80];	// メッセージ領域
	BREGEXP *rxp = NULL;	// 必ずクリアしておくこと 
	// 変換文字サンプル
	char t1[] = " Yokohama 045-222-1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 ";
	char patern1[] = "tr/A-Z0-9/a-zx/g";
	int ctr;
	if (ctr = BTrans(patern1,t1,t1+lstrlen(t1),&rxp,msg)) {
		printf("after(%d)=%s\n",ctr,rxp->outp);	// 変換した文字数と文字列
		printf("length=%d\n",rxp->outendp - rxp->outp);	// 変換後の文字数
	}

	if (rxp)				// コンパイルブロックの開放
		BRegfree(rxp);		// 忘れないように


結果:
after(33)= yokohama xxx-xxx-xxxx  osaka xx-xxxx-xxxx  tokyo xx-xxxx-xxxx 
length=63


BSplit関数のサンプル

電話番号をデリミタとして文字列を分割します。
	BREGEXP *rxp = NULL;	// 必ずクリアしておくこと 
	char msg[80];
	char t1[] = " Yokohama 045-222-1111  Osaka 06-5555-6666  Tokyo 03-1111-9999 ";
	char patern1[] = "/ *\\d{2,3}-\\d{3,4}-\\d{4} */";
   	int splitcnt = BSplit(patern1,t1,t1+lstrlen(t1),0,&rxp,msg);
	if (splitcnt > 0 ) {
		int i = 0;
		for (int j = 0;j < splitcnt;j++) {
			int len = rxp->splitp[i+1] - rxp->splitp[i];
			char *tp = (char*)rxp->splitp[i];
			char ch = tp[len]; // save delmitter
			tp[len] = 0;	// set stopper
			printf("len=%d [%d]=%s\n",len,j,tp);
			tp[len] = ch;	// restore the char
			i += 2;
		}
	}

結果:
len=9 [0]= Yokohama
len=5 [1]=Osaka
len=5 [2]=Tokyo


Bregexpライブラリの使用上のご注意

Bregexp ライブラリは、Perl 5 ソースをベースに作成されてますので Perl のArtistic ライセンスが適用されてます。 詳細は、パッケージの中の perl_license.txt をご覧ください。

Home


Copyright 1999-2000 Tatsuo Baba,All rights reserved.