あなたはほとんど正しいです。引用符が必須であると仮定すると、scan-set 変換指定子を引用符で囲む必要があります。
if (sscanf(s, "%*s \"%29[^\"]\" %d", name, &date) != 2)
...oops...
に注意してください%29[^0-9]
。'\0'
これにより、文字列が 29 バイトと30 バイトの配列に収まる終端の null に制限されます。アウターにも同様のチェックを入れるか、代わりにscanf()
使用する必要があります。fgets()
scanf()
引用符がオプションの場合は、数字以外の名前をスキャンし、スキャン後に引用符を削除するという、少し手間がかかる作業が必要です。
if (sscanf(s, "%*s %29[^0-9] %d", name, &date) != 2)
...oops...
ここにいくつかのテストコードがあります:
#include <stdio.h>
static void scanner(const char *fmt, const char *s)
{
char name[30];
int date;
if (sscanf(s, fmt, name, &date) != 2)
printf("Scan failed {%s} and {%s}\n", fmt, s);
else
printf("{%s} and {%s} => {%s} %d\n", fmt, s, name, date);
}
int main(void)
{
char source[][30] =
{
"ins \"name in quotes\" 12345",
"ins name without quotes 12345",
};
enum { NUM_SOURCE = sizeof(source) / sizeof(source[0]) };
char format[][20] =
{
"%*s \"%29[^\"]\" %d",
"%*s %29[^0-9] %d",
};
enum { NUM_FORMAT = sizeof(format) / sizeof(format[0]) };
for (int i = 0; i < NUM_FORMAT; i++)
{
for (int j = 0; j < NUM_SOURCE; j++)
scanner(format[i], source[j]);
}
return 0;
}
出力例:
{%*s "%29[^"]" %d} and {ins "name in quotes" 12345} => {name in quotes} 12345
Scan failed {%*s "%29[^"]" %d} and {ins name without quotes 12345}
{%*s %29[^0-9] %d} and {ins "name in quotes" 12345} => {"name in quotes" } 12345
{%*s %29[^0-9] %d} and {ins name without quotes 12345} => {name without quotes } 12345
変換の失敗は予期されたものです。フォーマットは引用符を探しますが、何もありません。
少し異なるハーネスとフォーマット文字列も試しました。
"%*s %1[\"]%29[^\"]%1[\"] %d"
(引用符を保持するために 2 つの 2 文字の文字列q1
とq2
, を渡す) が、引用符が欠落している場合、スキャンは失敗しました。引用符はオプションではありません。
名前には末尾のスペースと 2 番目の形式の引用符があることに注意してください。それらは個別に削除する必要があります。