トークン化

トークン化とは、長い文字列を短い文字列へ分割する処理です。ここでは、区切りとして働く別の文字列を指定して分割します。たとえば、次の文字列には、|-|という区切りで分けられた2つの部分文字列があります。

foo|-|bar|-|zap

1文字からなる、より一般的な区切りはコンマです。

foo,bar,zap

多くのプログラムでは、1行を処理して、その構成要素である部分文字列を取り出すと便利です。そのため、SDSには、文字列と区切りを渡すとSDS文字列の配列を返す関数があります。

sds *sdssplitlen(const char *s, int len, const char *sep, int seplen, int *count);
void sdsfreesplitres(sds *tokens, int count);

通常どおり、この関数はSDS文字列と通常のC文字列の両方を扱えます。最初の2引数sとlenはトークン化する文字列を指定し、次の2引数sepとseplenはトークン化に使う区切りを指定します。最後の引数countは整数へのポインターで、返されたトークン(部分文字列)の数が設定されます。

戻り値は、ヒープ上に確保されたSDS文字列の配列です。

sds *tokens;
int count, j;

sds line = sdsnew("Hello World!");
tokens = sdssplitlen(line,sdslen(line)," ",1,&count);

for (j = 0; j < count; j++)
    printf("%s\n", tokens[j]);
sdsfreesplitres(tokens,count);

output> Hello
output> World!

返される配列はヒープ上に確保され、各要素は通常のSDS文字列です。例のようにsdsfreesplitresを呼ぶと、すべてを解放できます。また、free関数で配列だけを自分で解放し、個々のSDS文字列は通常どおり使ったり、解放したりしてもかまいません。

何らかの形で再利用した配列要素をNULLに設定し、sdsfreesplitresで残りをすべて解放する方法も有効です。

コマンドライン向けのトークン化

区切りによる分割は便利ですが、多少複雑な文字列操作を要する典型的な作業である、プログラムのコマンドラインインターフェースの実装には、通常それだけでは足りません。

そのため、SDSには、利用者がキーボードで対話的に入力した引数や、ファイル、ネットワークなどから渡した引数を、トークンへ分割する追加の関数もあります。

sds *sdssplitargs(const char *line, int *argc);

sdssplitargs関数は、sdssplitlenと同じくSDS文字列の配列を返します。結果を解放する関数も同じsdsfreesplitresです。違いは、トークン化の方法にあります。

たとえば、入力が次の行だった場合:

call "Sabrina"    and "Mark Smith\n"

関数は次のトークンを返します。

  • "call"
  • "Sabrina"
  • "and"
  • "Mark Smith\n"

基本的に、トークン同士は1つ以上の空白で区切る必要があります。また、各トークンには、sdscatreprが出力できるものと同じ形式の引用表現の文字列も使えます。

文字列の結合

トークン化の逆に、複数の文字列を1つへ結合する関数が2つあります。

sds sdsjoin(char **argv, int argc, char *sep, size_t seplen);
sds sdsjoinsds(sds *argv, int argc, const char *sep, size_t seplen);

両関数は、要素数argcの文字列配列と、区切りおよびその長さを入力として受け取ります。そして、指定したすべての文字列を、指定した区切りでつないだSDS文字列を出力します。

sdsjoinとsdsjoinsdsの違いは、前者がNUL終端されたC文字列を入力として受け取るのに対し、後者は配列内のすべての文字列がSDS文字列であることを要求する点です。このため、バイナリーデータを扱えるのはsdsjoinsdsだけです。

char *tokens[3] = {"foo","bar","zap"};
sds s = sdsjoin(tokens,3,"|",1);
printf("%s\n", s);

output> foo|bar|zap

エラー処理

SDSポインターを返す関数はすべて、メモリー不足の場合にNULLを返す可能性もあります。基本的には、これだけを確認すれば十分です。

ただし、現代のCプログラムの多くは、メモリー不足になると単にプログラムを中止します。同じ方法を取りたい場合は、mallocなど、関連するメモリー確保の呼び出しを直接ラップするとよいでしょう。