🖥️

【C言語超入門】 第24回 日本語の文字列操作

に公開

https://youtu.be/QZhc8eKb56M

四国めたん
\textcolor{pink}{四国めたん: }教師役ですわ

ずんだもん
\textcolor{lime}{ずんだもん: }生徒役なのだ

\footnotesize \textcolor{pink}{四国めたん:} 皆さん、こんにちは。四国めたんです

\footnotesize \textcolor{lime}{ずんだもん:} ずんだもんなのだ。こんにちはなのだ

\footnotesize \textcolor{pink}{四国めたん:} 今回もC言語のお勉強をしていきましょう

\footnotesize \textcolor{lime}{ずんだもん:} レッツゴーなのだ

\footnotesize \textcolor{pink}{四国めたん:} 前回は文字列に対する操作についてお話ししましたわ

\footnotesize \textcolor{lime}{ずんだもん:} うむ、いろいろな関数があったのだ

\footnotesize \textcolor{pink}{四国めたん:} ただ、対象は英語のみで、日本語を含む文字列に対しては色々と問題が発生しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 日本語の文字列に使えないのは残念なのだ

\footnotesize \textcolor{pink}{四国めたん:} ですので、今回は日本語を含む文字列に対する操作について、幾つかの関数を見ていきますわ

\footnotesize \textcolor{lime}{ずんだもん:} お~、待っていたのだ

\footnotesize \textcolor{pink}{四国めたん:} なお、今回お話しする関数はVisual Studioでのみ使える関数ですわ

\footnotesize \textcolor{lime}{ずんだもん:} そうなのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、他の環境では使用できない可能性が高いので、その点は注意が必要ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 他の環境でも使用できる標準の関数はないのか?

\footnotesize \textcolor{pink}{四国めたん:} 汎用に使用できる標準関数も存在しますが、今は置いておきますわ

\footnotesize \textcolor{lime}{ずんだもん:} ぶ~ぶ~

\footnotesize \textcolor{pink}{四国めたん:} 基本的な日本語を含む文字列操作の関数は"mbstring.h"で宣言されているので、最初にインクルードしますわ

\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ

日本語の文字の型はchar型ではありません

\footnotesize \textcolor{pink}{四国めたん:} とりあえず、今回扱う日本語の文字についてお話ししますわ

\footnotesize \textcolor{lime}{ずんだもん:} よろしくなのだ

\footnotesize \textcolor{pink}{四国めたん:} 今までの文字は ASCIIコード と云う0~127の1バイトの整数を英数字や記号等に当てはめて使っていましたわ

\footnotesize \textcolor{lime}{ずんだもん:} char型 で扱っていたのだ

\footnotesize \textcolor{pink}{四国めたん:} 日本語を含む文字のコードは、JISで決められていますわ

\footnotesize \textcolor{lime}{ずんだもん:} コードをそのまま使うのか

\footnotesize \textcolor{pink}{四国めたん:} いいえ、Windowsでは Shift_JIS によって符号化して使いますわね

\footnotesize \textcolor{lime}{ずんだもん:} 符号化?

\footnotesize \textcolor{pink}{四国めたん:} はい、ASCIIコードを1バイトに、JISの日本語の文字のコードを2バイトで表せるように、少し細工をしていますわね

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{lime}{ずんだもん:} ところで2バイトの文字があるのでは、 char型 では扱えないのではないか?

\footnotesize \textcolor{pink}{四国めたん:} 基本的には unsigned char型 の配列やそのポインタを使うようになっていますわ

\footnotesize \textcolor{lime}{ずんだもん:} unsigned char

\footnotesize \textcolor{pink}{四国めたん:} unsigned charは、1バイトで0x00(0)から0xFF(255)までの正の整数を表す型ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 負数がないからunsignedなのか

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{lime}{ずんだもん:} でも同じ1バイトの型なら、2バイトの日本語の文字は入れられないのではないか?

\footnotesize \textcolor{pink}{四国めたん:} はい、その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} ですので、2バイトの日本語の文字は、 unsigned char型配列 に入れますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

Unicode

日本語を含む文字のコードはJIS(JIS X 0208)の他に、世界標準の Unicode という規格が存在します

Unicode は日本語だけではなく、世界中の文字がコードとして収録されています

音符などの記号も数多く収録されています

ピカド(SFテレビドラマ スタートレック から派生したクリンゴン語を表すための架空の文字)なども収録されているなど、その文字数は膨大です

これらの文字のコードは、コンピューターで扱いやすいように、符号化、つまりデータの変換が行われて使用されます

符号化の方法は幾つか存在しますが、 UTF-8 UTF-16 UTF-32 などがよく使われます

未だにWindowsでは Shift_JIS が主流ですが、世界的な流れとしては UTF-8 が主流となりつつあります

WEBの世界では、ほぼ UTF-8 に統一されたと云って良いでしょう

その辺りの扱いについては、 入門 のレベルではありませんので、そのうち説明します(できればいいな)

_mbscpy_s

\footnotesize \textcolor{pink}{四国めたん:} まず最初は_mbscpy_sですわ

\footnotesize \textcolor{lime}{ずんだもん:} strncpyの日本語版か?

\footnotesize \textcolor{pink}{四国めたん:} その通りですが、strcpy_sの方が近いですわね

\footnotesize \textcolor{pink}{四国めたん:} 動作も同じで、指定した日本語の文字列をコピーしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 形式も同じなのか?

\footnotesize \textcolor{pink}{四国めたん:} 形式はstrcpy_sと似て、errno_t _mbscpy_s(unsigned char* dst, rsize_t size, const unsigned char* src)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 詳細について教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、コピー元のポインタをsrcに、コピー先のポインタをdstにセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} strncpyと同じで、元のデータは残ると思っていいのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、制限も同じで、コピー元とコピー先のメモリ領域が重なっていてはいけませんわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} そして、コピー先のメモリ領域のサイズをバイト単位でsizeにセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} rsize_tとはなんなのだ?

\footnotesize \textcolor{pink}{四国めたん:} rsize_tsize_tとおおむね同じ型ですわ

\footnotesize \textcolor{lime}{ずんだもん:} 戻り値はerrno_tとなっているが、なんなのだ?

\footnotesize \textcolor{pink}{四国めたん:} errno_tintとおおむね同じで、関数の成否が返りますわ

\footnotesize \textcolor{pink}{四国めたん:} コピーが成功すれば0が、失敗すれば0以外のエラーコードが返りますわね

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ではサンプルコードを見ていきましょう

#include <mbstring.h>
#include <stdio.h>
#include <stdlib.h>

#define SIZE (20)

void main() {
  unsigned char c[] = "これはpenです.";  // 14バイト+NUL終端
  unsigned char* p = (unsigned char*)malloc(SIZE);

  if (p != NULL) {
    errno_t err = _mbscpy_s(p, SIZE, c);
    if (err == 0) {
      printf("%s\n", p);
    }
  }
  free(p);
  p = NULL;
}

_mbscpy_sの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「これはpenです.」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、まずは先頭で"mbstring.h"をインクルードしていますわ

\footnotesize \textcolor{lime}{ずんだもん:} #include <mbstring.h>の部分なのだ

\footnotesize \textcolor{pink}{四国めたん:} そして、文字列としてはASCIIコードで表せる文字は1バイト、それ以外は2バイトなので、14バイトとなりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 終端文字を含めて15バイトの配列となるのだ

\footnotesize \textcolor{pink}{四国めたん:} コピー先のメモリ領域はmallocで確保していますわ

\footnotesize \textcolor{lime}{ずんだもん:} SIZEを20にして20バイト分を確保しているのだ

\footnotesize \textcolor{pink}{四国めたん:} 15バイト以上であれば問題ありませんわ

\footnotesize \textcolor{pink}{四国めたん:} そして、コピーが成功すれば、コピーされた文字列をprintfで表示していますわ

\footnotesize \textcolor{lime}{ずんだもん:} 最後に確保したメモリ領域を解放しているのだ

_mbslen

\footnotesize \textcolor{pink}{四国めたん:} つぎは_mbslenですわ

\footnotesize \textcolor{lime}{ずんだもん:} strlenの日本語版か?

\footnotesize \textcolor{pink}{四国めたん:} はい、日本語の文字列の長さを取得しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 文字列の長さ、つまり文字数が返るのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、バイト数ではありませんので、気を付けて下さいね

\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ

\footnotesize \textcolor{pink}{四国めたん:} 形式としてはsize_t _mbslen(const unsigned char* str)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 文字列の先頭のポインタをstrにセットするのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、そして戻り値には文字列の長さが返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} とりあえず、具体例をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ

#include <mbstring.h>
#include <stdio.h>
#include <stdlib.h>

#define SIZE (20)

void main() {
  unsigned char c[] = "これはpenです.";  // 9文字(14バイト)+NUL終端
  unsigned char* p = (unsigned char*)malloc(SIZE);

  if (p != NULL) {
    errno_t err = _mbscpy_s(p, SIZE, c);
    if (err == 0) {
      size_t len = _mbslen(p);
      printf("%sの長さは%lluです\n", p, len);
    } else {
      printf("コピーに失敗しました\n");
    }
  }
  free(p);
  p = NULL;
}

_mbslenの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「これはpenです.の長さは9です」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、mallocで確保したメモリ領域に文字列をコピーして、長さを取得していますわ

\footnotesize \textcolor{lime}{ずんだもん:} なぜ文字列をコピーしているのだ?

\footnotesize \textcolor{pink}{四国めたん:} 前のプログラムを流用した結果ですわね

\footnotesize \textcolor{lime}{ずんだもん:} 特に意味はないのか...

\footnotesize \textcolor{pink}{四国めたん:} _mbslenの戻り値については、文字列の文字数9で、バイト数14ではないことに注意して下さいね

\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ

_mbstrlen

Visual Studioには_mbslenと同じような関数_mbstrlenも提供されています

基本的な動作や形式は同じです

違いは_mbslenの場合は文字列が有効かどうかのチェックが行われませんが、_mbstrlenの場合はチェックされます

通常は有効ではない文字列を扱うことはないので、どちらを使っても問題ありません

_mbsncat_s

\footnotesize \textcolor{pink}{四国めたん:} 次は_mbsncat_sですわ

\footnotesize \textcolor{lime}{ずんだもん:} strncatの日本語版か?

\footnotesize \textcolor{pink}{四国めたん:} その通りで、指定した日本語の文字列を連結しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 形式はどうなのだ?

\footnotesize \textcolor{pink}{四国めたん:} 形式としてはerrno_t _mbsncat_s(unsigned char* dst, size_t num, const unsigned char* src, size_t count)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} strncatとは違っているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、連結元の文字列のポインタをsrcに、連結先の文字列のポインタをdstにセットしますわ

\footnotesize \textcolor{pink}{四国めたん:} なお、文字列の連結ですので、連結元と連結先のメモリ領域が重なっていてはいけませんわ

\footnotesize \textcolor{lime}{ずんだもん:} 気を付けるのだ

\footnotesize \textcolor{pink}{四国めたん:} 次に、連結先にコピーする文字列の文字数をcountにセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} バイト単位ではなく、文字数なのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、なお連結元の文字列を全てコピーする場合には_TRUNCATEをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} _TRUNCATE

\footnotesize \textcolor{pink}{四国めたん:} "mbstring.h"中で定められている定数ですわね

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} numには連結先のメモリ領域のサイズをバイト単位でセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 文字数ではなく、バイト単位なのだな

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} 戻り値は、連結が成功すれば0が、失敗すれば0以外のエラーコードが返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} りょうかいなのだ

\footnotesize \textcolor{pink}{四国めたん:} サンプルコードを見てみましょう

#include <mbstring.h>
#include <stdio.h>

#define SIZE (50)

void main() {
  unsigned char c1[SIZE] = "これはpenです.";  // 14バイト+NUL終端
  unsigned char c2[] = "これはappleです.";    // 16バイト+NUL終端

  errno_t err = _mbsncat_s(c1, SIZE, c2, _TRUNCATE);
  if (err == 0) {
    printf("%s\n", c1);
  }
}

_mbsncat_sの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「これはpenです.これはappleです.」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、問題なく文字列が連結されていますわね

\footnotesize \textcolor{lime}{ずんだもん:} 詳細の説明をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、まずc1を文字列として宣言、初期化していますわ

\footnotesize \textcolor{lime}{ずんだもん:} 配列のサイズをSIZEとして指定する必要があるのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、文字列を連結した後に必要なサイズの配列を確保する必要がありますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} 次にc2を文字列として宣言、初期化していますわ

\footnotesize \textcolor{lime}{ずんだもん:} c2は配列のサイズを指定しなくてもいいのか?

\footnotesize \textcolor{pink}{四国めたん:} 連結元の文字列は文字数分のサイズが確保されていればOKなので、サイズの指定は、いりませんわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} 引数numには、連結先のメモリサイズSIZEバイトを指定していますわ

\footnotesize \textcolor{lime}{ずんだもん:} c1c2を連結した後の文字列のサイズ、(14 + 16 + NUL終端)バイトには十分なサイズなのだ

\footnotesize \textcolor{pink}{四国めたん:} あとは_mbsncat_sで文字列を連結した後、printfで表示していますわ

_mbscmp

\footnotesize \textcolor{pink}{四国めたん:} 次は_mbscmpですわ

\footnotesize \textcolor{lime}{ずんだもん:} strcmpの日本語版か?

\footnotesize \textcolor{pink}{四国めたん:} はい、指定した日本語の文字列を比較して、同じかどうかをチェックしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 形式も同じなのか

\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはint _mbscmp(const unsigned char* str1, const unsigned char* str2)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 解説をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} まず、比較する日本語の文字列へのポインタをstr1str2にセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 戻り値は比較の結果か?

\footnotesize \textcolor{pink}{四国めたん:} はい、完全に一致していれば0が、一致していなければ0以外が返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} とりあえず、具体例をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ

#include <stdio.h>
#include <mbstring.h>

void main() {
  unsigned char c1[] = "これはpenです.";     // 14バイト+NUL終端
  unsigned char c2[] = "これはappleです.";   // 16バイト+NUL終端

  if (_mbscmp(c1, c2)) {
    printf("c1とc2は異なる文字列です\n");
  } else {
    printf("c1とc2は同じ文字列です\n");
  }
}

_mbscmpの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「c1とc2は異なる文字列です」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、_mbscmpは文字列が一致していないので0以外を返しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 0以外の整数ということは、真偽値ではtrueと同じということか

\footnotesize \textcolor{pink}{四国めたん:} はい、ですのでprintfでは「c1とc2は異なる文字列です」と表示されますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみに比較する文字列を変えて同じ内容にすれば、結果は「c1とc2は同じ文字列です」と表示されますわ

#include <mbstring.h>
#include <stdio.h>

void main() {
  unsigned char c1[] = "これはpenです.";     // 14バイト+NUL終端
  unsigned char c2[] = "これはpenです.";     // 14バイト+NUL終端

  if (_mbscmp(c1, c2)) {
    printf("c1とc2は異なる文字列です\n");
  } else {
    printf("c1とc2は同じ文字列です\n");
  }
}

_mbscmpの結果2

\footnotesize \textcolor{lime}{ずんだもん:} 確かに「c1とc2は同じ文字列です」と表示されたのだ

_mbsstr

\footnotesize \textcolor{pink}{四国めたん:} 次は_mbsstrですわ

\footnotesize \textcolor{lime}{ずんだもん:} strstrの日本語版か?

\footnotesize \textcolor{pink}{四国めたん:} はい、日本語の文字列から指定した文字列を検索しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 形式も同じなのか

\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはunsigned char* _mbsstr(const unsigned char* str1, const unsigned char* str2)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} 解説をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} まず、検索対象の日本語の文字列へのポインタをstr1にセットしますわ

\footnotesize \textcolor{pink}{四国めたん:} そして検索する日本語の文字列へのポインタをstr2にセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 戻り値は unsigned char型 のポインタなのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、検索対象中に検索文字列が含まれる場合には、最初にヒットした文字列の先頭へのポインタが返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} 検索文字列が見つからなかった場合にはどうなるのだ?

\footnotesize \textcolor{pink}{四国めたん:} 検索文字列が見つからなかった場合にはNULLが返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} サンプルコードを見てみましょう

#include <mbstring.h>
#include <stdio.h>

void main() {
  unsigned char c1[] = "これはpenです.";  // 14バイト+NUL終端
  unsigned char c2[] = "pen";
  unsigned char* p1 = _mbsstr(c1, c2);
  unsigned char* p2 = _mbsstr(c1, "は");

  if (p1 != NULL) {
    printf("pen以下の文字列は\"%s\"です\n", p1);
  }
  if (p2 != NULL) {
    printf("\"は\"以下の文字列は\"%s\"です\n", p2);
  }
}

_mbsstrの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「pen以下の文字列は"penです."です」、「"は"以下の文字列は"はpenです."です」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、どちらもちゃんと検索できましたわね

\footnotesize \textcolor{lime}{ずんだもん:} 解説をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、p1は文字列c1からc2を検索していますわ

\footnotesize \textcolor{lime}{ずんだもん:} c1にはc2の"pen"が含まれているので、p1には"p"へのポインタがセットされるのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、そしてp2は日本語の1文字の文字列"は"をc1から検索していますわ

\footnotesize \textcolor{lime}{ずんだもん:} c1には"は"が含まれているので、p2には"は"へのポインタがセットされるのだ

\footnotesize \textcolor{pink}{四国めたん:} そして得られたポインタからNUL終端までの文字列をprintfで表示していますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみに文字を検索する場合にはunsigned char* _mbschr(const unsigned char* str, unsigned int c)という別の関数があるので、そちらを使いますわ

\footnotesize \textcolor{lime}{ずんだもん:} 指定する文字は unsigned int型 だが問題ないのか?

\footnotesize \textcolor{pink}{四国めたん:} まぁ、サイズ2の unsigned char型 の配列は unsigned int型 よりサイズが小さいので、代入可能ですわ

\footnotesize \textcolor{lime}{ずんだもん:} わかったのだ

_mbstok

\footnotesize \textcolor{pink}{四国めたん:} 最後は_mbstokですわ

\footnotesize \textcolor{lime}{ずんだもん:} strtokの日本語版か

\footnotesize \textcolor{pink}{四国めたん:} はい、文字列を指定の区切り文字で分割しますわ

\footnotesize \textcolor{lime}{ずんだもん:} 形式も同じなのか

\footnotesize \textcolor{pink}{四国めたん:} はい、形式としてはunsigned char* _mbstok(unsigned char* str, const unsigned char* delimiters)となりますわ

\footnotesize \textcolor{lime}{ずんだもん:} ふむふむ

\footnotesize \textcolor{pink}{四国めたん:} なお、Visual Studioでは同様の関数としてunsigned char* _mbstok_s(unsigned char* str, const unsigned char* delimiters, char** context)が推奨されていますわ

\footnotesize \textcolor{lime}{ずんだもん:} とりあえず詳細について教えてほしいのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、最初の呼び出しでは、分割する文字列へのポインタをstrにセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 2回目以降の呼び出しではNULLをセットするのだったか?

\footnotesize \textcolor{pink}{四国めたん:} はい、_mbstokは複数回、呼び出すことが前提ですので、2回目以降の呼び出しではNULLをセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} 分割する文字列をセットするのは初回だけなのだな

\footnotesize \textcolor{pink}{四国めたん:} 次にdelimitersには分割に使用する区切り文字を文字列としてセットしますわ

\footnotesize \textcolor{lime}{ずんだもん:} たしか区切り文字は複数の指定ができるのだったな

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} そして戻り値には分割された文字列へのポインタが返りますわ

\footnotesize \textcolor{lime}{ずんだもん:} 戻り値は、呼び出し毎に1つの文字列へのポインタが返るのだったか?

\footnotesize \textcolor{pink}{四国めたん:} はい、、初回の呼び出しの戻り値には、分割された最初の文字列が返りますわ

\footnotesize \textcolor{pink}{四国めたん:} そして、2番目以降の分割された文字列は、続けて_mbstok関数を呼び出すことで取得しますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} 2番目以降の分割された文字列は、続けて_mbstok関数のstrNULLをセットして呼び出すことで得られますわ

\footnotesize \textcolor{lime}{ずんだもん:} 分割された文字列が無くなった場合には、NULLが戻り値として返るのだったな

\footnotesize \textcolor{pink}{四国めたん:} その通りですわ

\footnotesize \textcolor{pink}{四国めたん:} ではサンプルコードを見ていきましょう

#define _CRT_SECURE_NO_WARNINGS

#include <mbstring.h>
#include <stdio.h>

void main() {
  unsigned char c[] = "これはpenです。 これはappleです。";
  unsigned char* p = _mbstok(c, " 。");

  while (p != NULL) {
    printf("%s\n", p);
    p = _mbstok(NULL, " 。");
  }
}

_mbstokの結果

\footnotesize \textcolor{lime}{ずんだもん:} 「これはpenです」、「これはappleです」と表示されたのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、しっかりと句点"。"を区切りとして文字列の取得ができていますわね

\footnotesize \textcolor{lime}{ずんだもん:} プログラムの解説をおねがいするのだ

\footnotesize \textcolor{pink}{四国めたん:} わかりましたわ

\footnotesize \textcolor{pink}{四国めたん:} 最初の_mbstok関数のコールでは、分割する文字列cと区切り文字として空白 と句点を文字列として与えていますわ

\footnotesize \textcolor{lime}{ずんだもん:} 区切り文字は幾つでも指定できるのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、全ての区切り文字を文字列にまとめて指定しますわ

\footnotesize \textcolor{pink}{四国めたん:} その後はNULLが返るまで繰り返し_mbstok(NULL, " 。")を呼び出していますわ

\footnotesize \textcolor{lime}{ずんだもん:} pには文字列へのアドレスが入るのか?

\footnotesize \textcolor{pink}{四国めたん:} はい、_mbstokを呼び出す毎に区切り文字で区切られた文字列のアドレスが入りますわ

\footnotesize \textcolor{lime}{ずんだもん:} なるほどなのだ

\footnotesize \textcolor{pink}{四国めたん:} ちなみに unsigned char型 の配列としてのc_mbstok呼び出し後には変更されてしまいますわね

\footnotesize \textcolor{pink}{四国めたん:} ですので、cにはconstキーワードを付けてはいけませんわ

\footnotesize \textcolor{lime}{ずんだもん:} _mbstok関数が勝手に変更してしまうのか...

\footnotesize \textcolor{pink}{四国めたん:} まぁ、そういう意味でも珍しい関数ですわね

\footnotesize \textcolor{lime}{ずんだもん:} ところで#define _CRT_SECURE_NO_WARNINGSをファイルの最初に宣言しているのだ

\footnotesize \textcolor{pink}{四国めたん:} はい、_mbstok関数は、Visual Studioではエラーの対象なので必要ですわね

_mbstok_s

Visual Studioでは、_mbstokの代わりに_mbstok_sの使用を推奨しています

形式としてはunsigned char* _mbstok_s(unsigned char* str, const unsigned char* delimiters, char** context)です

_mbstokと比べてcontextが追加されています

contextは関数内部でのみ使用します

とりあえず char*型 の変数を宣言して、そのアドレスをセットします

具体的には以下のように使用します

#include <stdio.h>
#include <mbstring.h>

void main() {
  unsigned char c[] = "これはpenです。 これはappleです。";
  char* pcontext = NULL;
  unsigned char* p = _mbstok_s(c, " 。", &pcontext);

  while (p != NULL) {
    printf("%s\n", p);
    p = _mbstok(NULL, " 。", &pcontext);
  }
}

_mbstok_s_mbstokと比べてセキュリティが向上しています

ただ、基本的には複雑な使い方をしなければ_mbstokで十分です

まとめ

\footnotesize \textcolor{pink}{四国めたん:} お疲れさまでした

\footnotesize \textcolor{lime}{ずんだもん:} おつかれさまなのだ

\footnotesize \textcolor{pink}{四国めたん:} 以上で 日本語の文字列操作 についての説明は終わりですわ

Discussion