「コピペ」で試して使える SLLIB 実用コード集

C言語で 「正規表現を使った文字列操作」 「文字列配列」 「連想配列」 「圧縮ファイルの読み書き」 等々が簡単に扱えるという事を, すぐに試せる具体例で示してみます.

現在,毎日1つずつくらいを目安に増やしています. ぼちぼちいきますので気長にお待ちください.


目次


ハローワールドと標準エラー出力

#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()でフラッシュできます.


テキストファイル(URLや圧縮ファイルもOK)を1行ずつ読む

#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

内部バッファの大きさは自動調整されるので, バッファの大きさを気にする事なく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()を使います.


文字列に対して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;                       /* 文字列オブジェクト */
    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つのみ置換します.


POSIX拡張正規表現によるパターンマッチ

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)を返します. 失敗した場合は負の値を返します.


「sed -e …」と同じ感覚で,正規表現で文字列置換

後方参照を使って, 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」になります.