C言語を使う仕事が終わりかけなので自作関数備忘録。
split
配列ではなく、区切り文字までを元の文字列から取り除き、取得する。
これがしたい
char token[4] = {0};
char str[] = "a,,c";
getFirstToken(token, ",", str); // token[0] = "a", str = ",c"
getFirstToken(token, ",", str); // token[1] = "", str = "c"
getFirstToken(token, ",", str); // token[2] = "c", str = ""
getFirstToken(token, ",", str); // token[2] = "", str = ""
標準ライブラリのstrtok_sを使っていたが、空白を飛ばしてしまうのが不都合だった(上の例でいえば、token[1]="c"になる)。
GetFirstToken
//最初のトークンを取得し、元の文字列からは消去
//Shift_JIS未対応
VOID GetFirstToken(CHAR* token, CHAR* delimiter, CHAR* string)
{
if (string[0] == '\0') {
token[0] = '\0';
return;
}
CHAR* p = strstr(string, delimiter);
if (p == string) {
strcpy_s(string, strnlen_s(string, DATA_LINE_MAX_LENGTH), string + DELIMITER_LENGTH);
token[0] = '\0';
return;
}
// If Last token, make the original string empty and return.
if (p == NULL) {
for (int i = 0; i <= strnlen_s(string, DATA_LINE_MAX_LENGTH); i++) {
if (string[i] == '\0') {
token[i] = '\0';
string[0] = '\0';
return;
}
token[i] = string[i];
}
}
for (int i = 0; i < p - string; i++) {
token[i] = string[i];
}
token[p - string] = '\0';
strcpy_s(string, strnlen_s(string, DATA_LINE_MAX_LENGTH), p + 1);
}
欠点
- 1バイトずつチェックしているので、Shift_JISのダメ文字が含まれていると文字化けする。
例えば、delimiterが"|"(文字コード7c)だった場合、「ポ」(83 7c),「弓」(8b 7c),「竹」(92 7c)などは2バイト目が区切り文字と同じになり、1バイト目と2バイト目を別々のascii文字として読むため文字化けする。ダメ。 -
strtok_sの挙動をまねようとしている割にはポインタを返していない。 - 文字列の最後が空文字だった場合に、tokenの数が未知だと空文字なのか全トークン取得済みなのか判別できない
replace
ほとんどこの記事のまんま。http://urin.github.io/posts/2018/replace-string-by-c-lang
変数名からすべてめちゃくちゃ読みやすかった。
"\" → "\\"のように、、置換後の文字が置換前の文字を含んでいると変な感じになったので、最後にポインタをずらす処理を追加している。
replace
//2文字まで→3文字までの置換しか対応していない。数字は変えられる
CHAR* replace(CHAR str, CHAR replaced, CHAR* substitution) {
CHAR* replacedPos = str;
size_t lenReplaced = strnlen_s(replaced, 2);
size_t lenSub = strnlen_s(substitution, 3);
while ((replacedPos = strstr(replacedPos, replaced)) != NULL) {
CHAR *lastPart = replacedPos + lenReplaced;
memmove(replacedPos + lenSub, lastPart, strlen(lastPart) + 1);
memcpy(replacedPos, substitution, lenSub);
replacedPos += lenSub;
}
return str;
}