C言語で、
char buf[100]="\"日 本 語 12 3\"," ",,\"aa\",,2,\"\",\"aaa\"";
から
para1=日 本 語 12 3
para2=<空白>
para3=なし
para4="aa"
para5=(なし)
para6=2
para7=(なし)
para8=aaa
を取得するようなうまい方法はありませんか。
条件
1)項目はカンマでくぎってあるとする
2)項目に値がない場合として、""あるいは何もない場合がある。
3)""の中の値には日本語や英数字が入っている。

OSはSolaris(UNIX)です。
よろしくお願いいたします。

このQ&Aに関連する最新のQ&A

A 回答 (2件)

bufの中身は恐らく変わるんですよね?


だとすればsscanfでの値取得は不可能だと思います。

標準関数のstrtokではヌル文字列が取れないので、ヌル文字列も取得できる拡張strtok関数を作ればいいのではないでしょうか。
(ただし分離記号は1つとし、切り出したトークンを囲むダブルクォートは除去します。)

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

char *ex_strtok(char *ptr, int delim)
{
static char *sptr = NULL;
char *tok, *p;

if (ptr != NULL) { sptr = ptr; }     /* 初回は文字列をセット */
else if (sptr == NULL) { return NULL; }  /* 取れない場合NULLを返す */

tok = sptr;
if (p = strchr(sptr, delim)) {      /* delimを探す */
sptr = p + 1;                /* sptrを次の先頭へ */
} else {
p = sptr + strlen(sptr);          /* pを文字列終端へ */
sptr = NULL;                /* 次回はNULLを返す */
}

if (*tok == '\"') {            /* 先頭が"なら */
tok++;                    /* 頭の"はスキップ */
*(p-1) = '\0';                /* 尾の"は\0に変換 */
}

*p = '\0';                 /* 分離記号を\0に変換 */

return tok;               /* トークンを返す */
}

int main(void)
{
char buf[100]="\"日 本 語 12 3\",\" \",,\"aa\",,2,\"\",\"aaa\"";
char *para;

para = ex_strtok(buf, ','); /* 最初はbufをセット */
do {
printf("<%s>\n", para);
} while (para = ex_strtok(NULL, ',')); /* 次回以降はNULLでコール */

return 0;
}


実行結果
<日 本 語 12 3>
< >
<>
<aa>
<>
<2>
<>
<aaa>

これならbufの中に、いくつパラメータがあってもOKでしょ?
ただしex_strtokは、strtok同様に、第1引数の文字列を変更してしまいますので、元の値が必要な場合は、作業領域にコピーしてから実行してください。
    • good
    • 0

ギブアップ。



専用の関数を作らないと駄目でしょう。ダブルクォーテーションを
削除していませんが、こんな感じか。


#include <stdio.h>
#include <stdarg.h>

void split_by(
  char *str,
  char sep,
  ...
  )
{
  va_list ap;
  char* to;
  char* p;

  va_start(ap, sep);
  to = va_arg(ap, char*);
  p = str;
  while (*p)
  {
    if (*p == sep)
    {
      *to = '\0';
      to = va_arg(ap, char*);
    }
    else
    {
      *to++ = *p;
    }
    ++p;
  }
  *to = '\0';
  va_end(ap);
}

int main(void)
{
  char buf[100]="\"日 本 語 12 3\",\" \",,\"aa\",,2,\"\",\"aaa\"";
  char para1[30], para2[30], para3[30], para4[30], para5[30], para6[30], para7[30], para8[30], para9[30];

  split_by(buf, ',', para1, para2, para3, para4, para5, para6, para7, para8, para9);

  printf("para1=<%s>\n", para1);
  printf("para2=<%s>\n", para2);
  printf("para3=<%s>\n", para3);
  printf("para4=<%s>\n", para4);
  printf("para5=<%s>\n", para5);
  printf("para6=<%s>\n", para6);
  printf("para7=<%s>\n", para7);
  printf("para8=<%s>\n", para8);
  printf("para9=<%s>\n", para9);

  return 0;
}

実行結果。

para1=<"日 本 語 12 3">
para2=<" ">
para3=<>
para4=<"aa">
para5=<>
para6=<2>
para7=<"">
para8=<"aaa">
para9=<>
    • good
    • 0

このQ&Aに関連する人気のQ&A

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人が検索しているワード

このQ&Aと関連する良く見られている質問

Qfgetsで拾われる改行文字を削除したい

お世話になります

 C言語初心者のものです。今課題でC言語を用いたプログラミングを
Fedora上でやっています。問題は、fgetsでテキストファイルから、取得
した文字列の中から改行文字を削除できないことです。文字変数のアド
レスはわかっているのですが、終端文字に置換しようとすると、セグメ
ントエラーになってしまいます。これは如何にして解決すべきでしょう
か。よろしくお願いします。

Aベストアンサー

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが最大文字数に達したり、ファイルの最後になったりで、strに改行文字が含まれない場合には、このループは止まりません(Segmentension Falutになって止まる)

・そのような状態になってないか、予めチェックする
・ループを終了させる仕組みを用意しておく
: forの終了条件を記述する、for中で if(*(str+i)=='\0') { break;} 等としておく、等
といった対策が必要です。


あと細かいところを言えば
・strを配列で用意したなら *(s+i)じゃなくてs[i]でいいんじゃないかな
・あるいは char *pみたいにしておいて、 iのループでなく pでループを組む( for(p=str;*p!='\0';p++) )とか。

ポインタとかアドレスとか、C言語の用語としてあるものを別の意味に使うとまぎらわしいです。

「ポインタ」「アドレス」と言われたら、 この例なら str, str+i が思い浮びます。
「文字変数のアドレス」だと
char c ;
に対しての
&c
が思い浮びます。

配列なら「添字」、意味的には「x文字目」ですね。

> for(i=0;;i++){
> if(*(str+i)=='/n') {
> *(str+i)='\0';
> break;
> }
> }
/nが\nの間違いなら、この方法で半分正解です。もう少し広い範囲(可能なら全体)で見ないことにはなんとも言えません。
fgetsが...続きを読む

QC言語のsscanf関数の上手な使い方

C言語で、
char buf[256];
char c1[10],c2[10],c3[10];
sscanf(buf,"%s%s%s",c1,c2,c3)
という、バッファから文字列を読み取るとき、
bufが、
"aa bb","aa,bb","aa, bb"の場合に、
c1 = "aa bb"
c2 = "aa,bb"
c3 = "aa, bb"
が入るようにする方法をご存知でしたら教えてください。
%[^\"]sを使ってみたのですが、c1しか格納できませんでした。
(条件)
" "かつ,で区切られた部分をパラメタに格納する。
" "内には、空白や,が入る。

Aベストアンサー

こんな感じ。

#include <stdio.h>

int main(void)
{
  char buf[256] = "\"aa bb\",\"aa,bb\",\"aa, bb\"";
  char c1[10], c2[10], c3[10];
  printf("%s\n", buf);
  sscanf(buf, "\"%[^\"]\",\"%[^\"]\",\"%[^\"]\"", c1, c2, c3);
  printf("c1=%s\n", c1);
  printf("c2=%s\n", c2);
  printf("c3=%s\n", c3);
  return 0;
}

Q構造体の初期化のmemsetの第三引数

memset(&lvitem, 0, sizeof(LVITEM));
memset(&lvitem, 0, sizeof(lvitem));
LVITEMに特化した質問ではなく構造体の初期化について、この2つの書き方によるソース管理やコンパイルでのメリットとデメリットを教えてください。

Aベストアンサー

(1)memset(&lvitem, 0, sizeof(LVITEM));
この書き方は、構造体LVITEMを初期化しているんだな、と分かりやすい。
(2)memset(&lvitem, 0, sizeof(lvitem));
この書き方はとにかく変数lvitemを初期化するんだな、という感じだが、型が分からないので宣言しているところを参照しなければならない。
それともう一つ、ただ単に何回も初期化するんでなければ、こういう書き方もできる。
(3)LVITEM lvitem = {0};

結局どれがいいのかといえば、個人的にはケースバイケースですねえ。初期化を1回すればいいような感じなら(3)、構造体名を明示した方が調べる手間がなくなるようなら(1)、そうでなければ(2)を使います。
コンパイルでのメリット、デメリットは特にないんじゃないかなあ。アセンブラがまだ全盛だった頃ならともかく、いまじゃどのコンパイラだって最適化オプションで同じようなコードはくでしょう。
気にするほどでもないと思うけど…


人気Q&Aランキング

おすすめ情報