split関数: 文字列を分割して配列に格納する
英文の単語切り出しをしようと他言語でよくある split 関数を作ってみた。
切り出す単語数が可変バージョンと、最大個数が決まっているバージョンの2パターンを作り、それぞれの長所と短所は以下の通り。
可変バージョン 長所:配列数は動的に決まるため、読む込む単語数を気にしなくて良い。 短所:呼出し側で malloc や free が必要。 固定バージョン 長所:malloc を使っていないので、free のし忘れの心配がない。 短所:配列数を静的に決める必要があるため、読み込む単語数に制限がある。引数が多い。
あと、strtok も評判悪そうなので、固定バージョンでは地道に走査させてみた。
こういう動く動かないの問題ではなくて、どちらが良いかという問題は非常に悩ましい。
// 可変バージョン #include <stdio.h> #include <stdlib.h> #include <string.h> #define ALLOCATE_SIZE 64 int split(char ***ary, const char *s, const char *delimiter) { char *tmp = strdup(s); int i, n; for (i = n = 0; (tmp = strtok(tmp, delimiter)) != NULL; i++) { if (i >= n) { n += ALLOCATE_SIZE; *ary = (char **)realloc(*ary, sizeof(char *) * n); } (*ary)[i] = strdup(tmp); tmp = NULL; } return i; } int main(void) { char str[] = "I stand here today humbled by the task before us, " "grateful for the trust you have bestowed, " "mindful of the sacrifices borne by our ancestors."; char delimiter[] = " "; int len, i; char **ary; ary = (char **)malloc(sizeof(char *)); len = split(&ary, str, delimiter); for (i = 0; i < len; i++) printf("%2d : [%s]\n", i, ary[i]); free(ary); return 0; }
// 固定バージョン #include <stdio.h> #include <stdlib.h> #include <string.h> #define BUF_SIZE 100 #define NELEMS(a) (sizeof(a) / sizeof(a[0])) static int in(const char *s, const char c); int split(char *ary[], int len, const char *s, const char *delimiter) { char buf[BUF_SIZE]; int i, j; for (i = 0; i < len && *s != '\0'; i++) { while (in(delimiter, *s)) s++; for (j = 0; j < BUF_SIZE && *s != '\0' && !in(delimiter, *s); j++, s++) buf[j] = *s; buf[j] = '\0'; if (j == 0) break; ary[i] = strdup(buf); } return i; } static int in(const char *s, const char c) { int i; for (i = 0; s[i] != '\0'; i++) if (s[i] == c) return 1; return 0; } int main(void) { char str[] = "I stand here today humbled by the task before us, " "grateful for the trust you have bestowed, " "mindful of the sacrifices borne by our ancestors."; char delimiter[] = " "; int len, i; char *ary[100]; len = split(ary, NELEMS(ary), str, delimiter); for (i = 0; i < len; i++) printf("%2d : [%s]\n", i, ary[i]); return 0; }