2014年9月15日月曜日

strtokっぽい関数

C言語のstring.hにはstrtokという関数があって、文字列を指定した区切り文字で分割することができます
しかしこの関数では区切り文字が連続した場合、その部分をまとめて次のデータに飛んでしまいます
この場合、CSVのヌルデータ等は正常に処理できません
ということでそのような連続した区切り文字が存在する場合も次に飛ばないような関数を作ってみました

#include <stdio.h>
#include <string.h>

char *strtoks(char *s1, const char *s2) {
    static char *str = 0;
    register int i, j;

    if (s1) {
        str = s1;
    } else {
        s1 = str;
    }
    if (!s1) { return(0); }

    j = strlen(s2);

    while (1) {
        if (!*str) {
            str = 0;
            return(s1);
        }

        for (i = 0; i < j; i++) {
            if (*str == s2[i]) {
                *str++ = 0;
                return(s1);
            }
        }

        str++;
    }
}

char *strtokc(char *s1, char s2) {
    static char *str = 0;

    if (s1) {
        str = s1;
    } else {
        s1 = str;
    }
    if (!s1) { return(0); }

    while (1) {
        if (!*str) {
            str = 0;
            return(s1);
        }

        if (*str == s2) {
            *str++ = 0;
            return(s1);
        }

        str++;
    }
}

int main(int argc, char *argv[]) {
    char str1[] = "10,20,30,,50,60,,,90";
    char str2[] = "10,20,30,,50,60,,,90";
    char str3[] = "10,20,30,,50,60,,,90";
    char *p;

    printf("strtok\n");
    p = strtok(str1, ",");
    while (p) {
        static int cnt = 0;
        printf("%d:\"%s\"\n", ++cnt, p);
        p = strtok(0, ",");
    }

    printf("\nstrtoks\n");
    p = strtoks(str2, ",");
    while (p) {
        static int cnt = 0;
        printf("%d:\"%s\"\n", ++cnt, p);
        p = strtoks(0, ",");
    }

    printf("\nstrtokc\n");
    p = strtokc(str3, ',');
    while (p) {
        static int cnt = 0;
        printf("%d:\"%s\"\n", ++cnt, p);
        p = strtokc(0, ',');
    }

    return(0);
}

上記のstrtoksとstrtokcが今回作った関数です
strtoksは複数の区切り文字のいずれかが出てきたらそこで区切ります
strtokcは区切り文字は文字列ではなく文字として渡します そのため若干パフォーマンスが向上します

実行結果は
strtok
1:"10"
2:"20"
3:"30"
4:"50"
5:"60"
6:"90"

strtoks
1:"10"
2:"20"
3:"30"
4:""
5:"50"
6:"60"
7:""
8:""
9:"90"

strtokc
1:"10"
2:"20"
3:"30"
4:""
5:"50"
6:"60"
7:""
8:""
9:"90"

という感じです
strtokではスキップしてしまうところも正常に処理しています
なお、strtoksおよびstrtokcのヌルデータはptr[0] = '\0'となっています
例えば整数型が入っていると仮定し、整数型から変換する関数に渡した場合、場合によっては問題が発生する可能性があります
その可能性が有る場合は最初にヌルデータか否かを確認する必要があります

あと、わざわざ説明する必要もないと思いますが、strtokや上記の関数は受け取ったデータを破壊します
char *str = "123,456,789"; p = strtok(str, ","); とかやらないよーに

1 件のコメント:

  1. すばらしいです。学校で同じ問題があり苦戦しています。ありがとうございました。

    返信削除