0

こんにちは、私はこのファイル構造を持っています:

0
2 4
0: 1(ab) 5(b)
1: 2(b) 6(a)
2: 0(a) 2(b)
3: 2(a) 6(b)
4: 5(ab)
5: 2(a) 6(b)
6: 4(b) 6(ab)

各行は、構造体にそのデータ (数字 + 文字) を供給します。
行を読み、必要な文字列を取得する最良の方法は何ですか?

例:

0
2 4
0,1,ab,5,b
1,2,b,5,a
...

1、2、3、.... の数を使用できるため、行のサイズが異なる場合があります。

私はすでにそれをやりました :

//struct 
#define MAX_ 20

struct otherstats{ //struct otherStats
  int conectstat[MAX_];//conection with others stats
  int transitions[MAX_];//Symbols betwen conection ASCI
}tableStats[MAX_];

struct sAutomate{
 int stat_initial; //initial
 int stats_finals[MAX_]; //final orfinals
 struct otherstats tableStats[MAX_]; //otherStats 0 1 2 3 4 5 6
};

/* eXample that what i want ..using the example 
sAutomate.stat_initial=0
sAutomate.stats_finals[0]=2
sAutomate.stats_finals[1]=4

Others Stats table
//0
sAutomate.tableStats[0].conectstat[0]=1;
sAutomate.tableStats[0].conectstat[1]=5;
sAutomate.tableStats[0].transitions[0]=ab;
sAutomate.tableStats[0].transitions[1]=b; 
//1
sAutomate.tableStats[1].conectstat[0]=2;
sAutomate.tableStats[1].conectstat[1]=6;
sAutomate.tableStats[1].transitions[0]=b;
sAutomate.tableStats[1].transitions[1]=a;
///etc
 */



void scanfile(){ //function to read the file

struct sAutomate st; //initialize st struct

char filename[] = "txe.txt";
FILE *file = fopen ( filename, "r" );
char buf[81];       
char parts[5][11];  

fscanf(file,"%d", &st.stat_initial);//read first line
printf("initial state : %d \n", st.stat_initial);
fscanf(file,"%d",&st.stats_finals);
fscanf(file,"%d",&st.stats_finals);


while (fgets(buf, sizeof(buf), stdin) != NULL)
{
if (sscanf(buf, "%10[^:]: (%10[^(], %10[^)]), (%10[^(], %10[^)])",
           parts[0], parts[1], parts[2], parts[3], parts[4]) == 5)
{
  printf("parts: %s, %s, %s, %s, %s\n",
         parts[0], parts[1], parts[2], parts[3], parts[4]);
}
else
{
  printf("Invalid input: %s", buf);
}
}
//fclose
4

2 に答える 2

1

私が見る最初の問題は、あなたが上書きしていることですstats_finals:

fscanf(file,"%d",&st.stats_finals);
fscanf(file,"%d",&st.stats_finals);

ここでやりたかったことは次のとおりです。

fscanf(file,"%d",&st.stats_finals[0]);
fscanf(file,"%d",&st.stats_finals[1]);

テキストファイルから「2」と「4」の両方を保存します。

2番目の大きな問題は、あなたが読んでいることですstdin:

while (fgets(buf, sizeof(buf), stdin) != NULL)

それはテキストファイルを読み取らず、キーボードからの入力を読み取ります...つまり、次のようにしたかったのです。

while (fgets(buf, sizeof(buf), file) != NULL)

3 番目の (マイナーな) 問題は、fscanf()改行を読み取らず、読み取るfgets()ことです。つまりstats_finals、while ループで 2 番目の読み取りから最初の読み取りに移動すると、最初の入力は改行文字の残りになります。「無効な入力」をチェックするので、それは大したことではありませんが、注目に値します。

最後に、あなたの sscanf は私には間違っているように見えます:

sscanf(buf, "%10[^:]: (%10[^(], %10[^)]), (%10[^(], %10[^)])",
               ^                        ^
              That's a width of 10,     Why are you checking for commas? You didn't
              I don't think that's      have any in your text file
              what you wanted...

これはあなたが探していたものだと思います:

sscanf(buf, "%[0-9]: %[0-9](%[^)]) %[0-9](%[^)])",
                ^
             takes a digit (0 to 9)

編集 元のポイントを逃しました。読んでいる文字列の長さが分からない場合は、 を使用できませんsscanf()。それはとても簡単です。:)

scanf ファミリは、解析するオブジェクトの数と、フォーマット文字列がその数を受け取ることを知っていることを前提としています。ただし、他のオプションもあります。

あなたがやっているようにfgetsで1行を読んでくださいが、それをトークン化することができます。C関数をstrtok使用するか、forループを使用して自分の手で行います。

ただし、次の点に注意してください。

どのくらいの長さかわからないので、これchar parts[5][11];は最善の策ではありません。これにより、2 つのエントリに制限されます...おそらくこれを動的に行う方がよいでしょう (行を読んでから、トークンを格納するための正しいサイズを割り当てます)。

于 2012-12-20T14:31:08.657 に答える
0

行に含まれる数字と文字の数が本当にわからない場合、なぜ一定量の数字と文字を読み取るのでしょうか?

で行全体を読み取ってから、次のようなfgetsトークナイザーで解析できます。strtok

const char* const DELIMITERS = " ";

int i;  // index for tableStats
char* token;

token = strtok(line, DELIMITERS);

// first integer
if (token == NULL || sscanf(token, "%d:", &i) < 1)
  // error

/* it seems like you should have at least one element in your "list",
 * otherwise this is not necessary
 */

token = strtok(NULL, DELIMITERS);

if (token == NULL || sscanf(token, "%d(%[^)])",
    &(tableStats[i].connectstat[0]),
    &(tableStats[i].transitions[0])) < 2)
  // error

// read optional part
for (int j = 1; (token = strtok(NULL, DELIMITERS)) != NULL; ++j)      
  if (sscanf(token, "%d(%[^)])", &(tableStats[i].connectstat[j]),
      &(tableStats[i].transitions[j])) < 3)
    break;

文字列がstrtok変更されることに注意してください。必要な場合はコピーを作成してください。

明らかに、コードは任意の長い行用であり、最初の 2 行を読むのは簡単です。

于 2012-12-20T14:52:35.087 に答える