0

C で複数の単語を含む行をスキャンしようとしています。単語ごとにスキャンし、各単語を異なる変数として格納する方法はありますか?

たとえば、次の種類の行があります。

A is the 1 letter;
B is the 2 letter;
C is the 3 letter;

最初の行を解析している場合:「A は 1 文字です」と次のコードがある場合、個々のトークンを取得して変数として格納できるように、それぞれの場合に何を入力すればよいでしょうか。明確にするために、このコードの終わりまでに、さまざまな変数に「is」、「the」、「1」、「letter」が必要です。

次のコードがあります。

while (feof(theFile) != 1) {
    string = "A is the 1 letter"
    first_word = sscanf(string);
    switch(first_word):
      case "A":
        what to put here?
      case "B":
        what to put here?
      ...     
4

4 に答える 4

2

そんな使い方はいけませんfeof()fgets()または同等のものを使用する必要があります。おそらくあまり知られていない (ただし標準の C89 には存在する) 変換指定子を使用する必要があります%n

#include <stdio.h>

int main(void)
{
    char buffer[1024];

    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        char *str = buffer;
        char word[256];
        int  posn;
        while (sscanf(str, "%255s%n", word, &posn) == 1)
        {
            printf("Word: <<%s>>\n", word);
            str += posn;
        }
    }
    return(0);
}

これは行を読み取り、sscanf()繰り返し使用して行から単語をフェッチします。フォーマット指定子は%n成功した変換にはカウントされないため、1 と比較します。 での%255sオーバーフローを防ぐために を使用していることに注意してくださいword。変換仕様で指定された 255 カウントの後に null を書き込む可能性があることにも注意してください。したがって、 の宣言と変換指定子sscanf()の違いは 1です。char word[256];%255s

明らかに、抽出された各単語をどう処理するかはユーザー次第です。ここのコードは単にそれを出力します。

に基づくソリューションに対するこの手法の利点の 1 つstrtok()sscanf()、入力文字列を変更しないため、エラーを報告する必要がある場合に、元の入力行をエラー レポートで使用できることです。


質問を編集した後、セミコロンのような句読点は一言で言えば不要のようです。上記のコードには、単語の一部として句読点が含まれます。その場合は、どうすればよいか、もう少し考えなければなりません。開始点は、次の代わりに変換仕様として英数字スキャンセットを使用することです%255s

"%255[a-zA-Z_0-9]%n"

おそらく、次のコンポーネントの先頭にある文字を見て、英数字でない場合はスキップする必要があります。

if (!isalnum((unsigned char)*str))
{
    if (sscanf(str, "%*[^a-zA-Z_0-9]%n", &posn) == 0)
        str += posn;
}

につながる:

#include <stdio.h>
#include <ctype.h>

int main(void)
{
    char buffer[1024];

    while (fgets(buffer, sizeof(buffer), stdin) != 0)
    {
        char *str = buffer;
        char word[256];
        int  posn;
        while (sscanf(str, "%255[a-zA-Z_0-9]%n", word, &posn) == 1)
        {
            printf("Word: <<%s>>\n", word);
            str += posn;
            if (!isalnum((unsigned char)*str))
            {
                if (sscanf(str, "%*[^a-zA-Z_0-9]%n", &posn) == 0)
                    str += posn;
            }
        }
    }
    return(0);
}

選択した英数字範囲の I18N および L10N の側面を考慮する必要があります。何が利用できるかは、実装によって異なります (POSIX では、残念ながらscanf()などの表記のスキャン セットでのサポートを指定していません)。[[:alnum:]]

于 2012-12-07T01:10:00.937 に答える
1

strtok()文字列をトークン化または分割するために使用できます。例については、次のリンクを参照してください: http://www.cplusplus.com/reference/cstring/strtok/

文字ポインタの配列を取り、それらにトークンを割り当てることができます。

例:

char *tokens[100];
int i = 0;
char *token = strtok(string, " ");
while (token != NULL) {
    tokens[i] = token;
    token = strtok(NULL, " ");
    i++;
}

printf("Total Tokens: %d", i);
于 2012-12-07T01:02:39.620 に答える
0

%s指定子が空白を取り除くことに注意してください。したがって、次のように書くことができます。

    std::string s = "A is the 1 letter";
    typedef char Word[128];
    Word words[6];
    int wordsRead = sscanf(s.c_str(), "%128s%128s%128s%128s%128s%128s", words[0], words[1], words[2], words[3], words[4], words[5] );
    std::cout << wordsRead << " words read" << std::endl;
    for(int i = 0;
        i != wordsRead;
        ++i)
        std::cout << "'" << words[i] << "'" << std::endl;

このアプローチが ( とは異なりstrtok)、読み取る単語の最大数とその長さに関する仮定を効果的に必要とすることに注意してください。

于 2012-12-07T01:04:36.887 に答える
0

を使用することをお勧めしstrtok()ます。http://www.cplusplus.com/reference/cstring/strtok/の例を次に示します。

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

int main ()
{
  char str[] ="- This, a sample string.";
  char * pch;
  printf ("Splitting string \"%s\" into tokens:\n",str);
  pch = strtok (str," ,.-");
  while (pch != NULL)
  {
    printf ("%s\n",pch);
    pch = strtok (NULL, " ,.-");
  }
  return 0;
}

出力は次のようになります。

Splitting string "- This, a sample string." into tokens:

This

a

sample

string

于 2012-12-07T01:07:06.157 に答える