トークン化
トークン化とは、長い文字列を短い文字列へ分割する処理です。ここでは、区切りとして働く別の文字列を指定して分割します。たとえば、次の文字列には、|-|という区切りで分けられた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など、関連するメモリー確保の呼び出しを直接ラップするとよいでしょう。