C言語で 「正規表現を使った文字列操作」 「文字列配列」 「連想配列」 「圧縮ファイルの読み書き」 等々が簡単に扱えるという事を, すぐに試せる具体例で示してみます.
現在,毎日1つずつくらいを目安に増やしています. ぼちぼちいきますので気長にお待ちください.
.printf()
, .eprintf()
.open()
, .getline()
, .chomp()
.printf()
[]
, .length()
, .assign()
.strreplace()
, .strspn()
,
.strcspn()
, .replace()
,
.put()
, .regreplace()
[]
,.length()
.strmatch()
.regmatch()
.regreplace()
.regassign()
#include <sli/stdstreamio.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; /* 標準入出力のためのオブジェクト */ sio.printf("Hello World\n"); /* stdout に出力 */ sio.eprintf("This is STDERR\n"); /* stderr に出力 */ return 0; }
ポイント:
.eprintf()
でstderrに出力します.
.flush()
,.eflush()
でフラッシュできます.
#include <sli/stdstreamio.h> #include <sli/digeststreamio.h> #include <sli/tstring.h> using namespace sli; int main() { stdstreamio sio; /* 標準入出力 */ digeststreamio f_in; /* 万能型ストリームI/O */ tstring line; /* 1行の文字列を保存するバッファ */ f_in.open("r", "http://www.ir.isas.jaxa.jp/index.html"); /* ファイルやURLをopen */ while ( (line=f_in.getline()) != NULL ) { /* 1行ずつ読む */ line.chomp(); /* 改行文字を削除 */ sio.printf("%s\n",line.cstr()); /* 表示する */ } f_in.close(); /* ストリームをclose */ return 0; }
ポイント: digeststreamioはURL(http://またはftp://)や圧縮ストリームも扱える 万能クラスです.
内部バッファの大きさは自動調整されるので, バッファの大きさを気にする事なくprintf()する事ができます.
#include <sli/stdstreamio.h> #include <sli/tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; /* 標準入出力 */ tstring my_str; /* 文字列オブジェクト */ my_str.printf("argc = %d", argc); /* 文字列オブジェクトに書き込み */ sio.printf("%s\n", my_str.cstr()); /* 表示 */ return 0; }
ポイント:
可変引数でない単純な文字列の代入の場合は.assign()
を使います.
#include <sli/stdstreamio.h> #include <sli/tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; /* 標準入出力 */ tstring my_str0, my_str1; /* 文字列オブジェクト */ size_t i; my_str0.assign("abcdefg"); /* 文字列オブジェクトに代入 */ for ( i=0 ; i < my_str0.length() ; i++ ) { /* my_str1 に1文字ずつ逆から代入 */ my_str1[my_str0.length()-1-i] = my_str0[i]; } sio.printf("my_str1 = [%s]\n", my_str1.cstr()); return 0; }
実行結果:
my_str1 = [gfedcba]
ポイント:
文字列オブジェクトに[]
がつくと,unsigned char
の文字コードを読み書きできます.
[]
の値が文字列長以上の場合は,
内部バッファのサイズを自動調整してくれますが,
文字列長がわかっている場合は
.resize(文字列長)
で事前に長さを変更しておいた方が実行コストがかかりません.
最も基本的なコードです. もちろん内部バッファの大きさは自動的に調整されます.
#include <sli/stdstreamio.h> #include <sli/tarray_tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; /* 標準入出力 */ tarray_tstring my_arr; /* 文字列配列オブジェクト */ size_t i; my_arr[0] = "fuji"; /* 代入 */ my_arr[2] = "hayabusa"; for ( i=0 ; i < my_arr.length() ; i++ ) { /* 表示 */ sio.printf("%zu: [%s]\n", i, my_arr[i].cstr()); } return 0; }
実行結果:
0: [fuji] 1: [] 2: [hayabusa]
ポイント:
tarray_tstring というのが文字列配列を扱うクラスです.
配列の長さは.length()
で取得します.
パターン「X*
」にマッチするかを表示するコードです.
#include <sli/stdstreamio.h> #include <sli/tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; /* 標準入出力 */ tstring my_str0, my_str1; /* 文字列オブジェクト */ my_str0.assign("X68030"); /* これらがマッチするかどうかを調べる */ my_str1.assign("FM-TOWNS"); /* マッチを試行 */ if ( my_str0.strmatch("X*") == 0 ) sio.printf("str0: OK!\n"); else sio.printf("str0: NG!\n"); if ( my_str1.strmatch("X*") == 0 ) sio.printf("str1: OK!\n"); else sio.printf("str1: NG!\n"); return 0; }
実行結果:
str0: OK! str1: NG!
ポイント:
先頭の「.」は特別扱いする(ファイル名向け)の.fnmatch()
,
「/」や「.」は特別扱いする(パス名向け)の.pnmatch()
もあります.
カンマ区切りの文字列を,2つの場合で置換してみます.
例1: カンマをセミコロンに置き換えてみます.
#include <sli/stdstreamio.h> #include <sli/tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; tstring my_str = "X1turboZIII , Z80A, MB89321B ,"; /* strreplace() は単純な文字列の置換を行なう */ my_str.strreplace(",", ";", true); sio.printf("result=[%s]\n", my_str.cstr()); return 0; }
結果
result=[X1turboZIII ; Z80A; MB89321B ;]
例2: 今度は,各要素を空白文字で上書きしてみます.
#include <sli/stdstreamio.h> #include <sli/tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; tstring my_str = "X1turboZIII , Z80A, MB89321B ,"; /* regreplace() は正規表現にマッチした部分の置換を行なう */ my_str.regreplace("[^,]", " ", true); sio.printf("result=[%s]\n", my_str.cstr()); return 0; }
結果
result=[ , , ,]
例3: 例2と同じ動作をするコードを
C言語風味の.strspn()
,.strcspn()
を使って書いてみます.
#include <sli/stdstreamio.h> #include <sli/tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; tstring my_str = "X1turboZIII , Z80A, MB89321B ,"; size_t spn0, spn1, pos; pos = 0; do { spn0 = my_str.strcspn(pos, ","); /* ','以外の文字が続く長さを調べる */ if ( 0 < spn0 ) { /* spn0個の空白で置き換える */ my_str.replace(pos, spn0, ' ', spn0); /* 文字数が変わらない場合,上書きをする .put() も使えます */ // my_str.put(pos, ' ', spn0); pos += spn0; } spn1 = my_str.strspn(pos, ","); /* ','が続く長さを調べる */ pos += spn1; } while ( 0 < spn0 || 0 < spn1 ); sio.printf("result=[%s]\n", my_str.cstr()); return 0; }
ポイント:
.strreplace()
,.regreplace()
の最後の引数をtrue
にセットすると,見つかった部分を
すべて置換します.false
の場合は,
最初の1つのみ置換します.
1つ前のコードと同じ事を 正規表現を使って行なっています.マッチした場合, マッチした部分の位置と長さとを表示します.
#include <sli/stdstreamio.h> #include <sli/tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; /* 標準入出力 */ tstring my_str0, my_str1; /* 文字列オブジェクト */ ssize_t matched_pos; /* マッチした位置を保存する変数 */ size_t matched_len; /* マッチした部分の長さを保存する変数 */ my_str0.assign("X68030"); /* これらがマッチするかどうかを調べる */ my_str1.assign("FM-TOWNS"); /* マッチを試行 */ matched_pos = my_str0.regmatch("^X.*",&matched_len); /* 結果を表示 */ if ( 0 <= matched_pos ) { sio.printf("str0: OK! pos=%zd len=%zu\n",matched_pos,matched_len); } else { sio.printf("str0: NG!\n"); } /* マッチを試行 */ matched_pos = my_str1.regmatch("^X.*",&matched_len); /* 結果を表示 */ if ( 0 <= matched_pos ) { sio.printf("str1: OK! pos=%zd len=%zu\n",matched_pos,matched_len); } else { sio.printf("str1: NG!\n"); } return 0; }
実行結果:
str0: OK! pos=0 len=6 str1: NG!
ポイント:
.regmatch()
はマッチに成功した場合,
マッチした部分の位置(0-indexed)を返します.
失敗した場合は負の値を返します.
後方参照を使って,
URL「http://darts.isas.jaxa.jp/foo/
」から
ホスト名「darts.isas.jaxa.jp
」を
取り出してみます.
#include <sli/stdstreamio.h> #include <sli/tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; tstring my_url = "http://darts.isas.jaxa.jp/foo/"; /* my_url に対して sed -e '...' のような置換を行なう */ my_url.regreplace("([a-z]+://)([^/]+)(.*)", "\\2"); sio.printf("hostname = %s\n", my_url.cstr()); return 0; }
実行結果:
hostname = darts.isas.jaxa.jp
文字列「"OS = linux"
」について,
キーワードと値とを取り出しています.
#include <sli/stdstreamio.h> #include <sli/tarray_tstring.h> using namespace sli; int main( int argc, char *argv[] ) { stdstreamio sio; tstring my_str = "OS = linux"; /* ←この文字列を分割してみる */ tarray_tstring my_elms; /* ←分割された文字列はここに入る */ /* 正規表現で分割 */ my_elms.regassign(my_str, "([^ ]+)([ ]*=[ ]*)([^ ]+)"); if ( my_elms.length() == 4 ) { sio.printf("keyword=[%s] value=[%s]\n", my_elms[1].cstr(), my_elms[3].cstr()); } return 0; }
実行結果:
keyword=[OS] value=[linux]
ポイント:
my_elms[0]
にはマッチした部分全ての文字列が格納されます.
したがって,.regassign()
後の文字列配列の個数は
「マッチした部分文字列の個数+1」になります.