ab
cd 0123
e 456
f
gh 7

のような英数字が混じったファイルを読み込み、数字が混じっている行のみを別のファイルに書き出すということをやりたいと思っています。
つまり

cd 0123
e 456
gh 7

のような形式で書き出したいわけです。
fgetsで1行ずつ読み込み、その行に数字が混じっていればfputsで書き出すというのは分かるのですが、「数字が混じっている」「混じっていない」の判定方法がわかりません。
strtodを使えば、英字のときは0が返ってくるのでそれをうまく使えば、と思って試行錯誤してみたのですが…
どなたかアドバイスをよろしくお願いします!

A 回答 (5件)

>fputs() だと、最後の '\n' は出力されません



最近はそうなのか・・・・知らなかった.
    • good
    • 0

albertpark> の部分は


albertpark> if (has_digit) {
albertpark> ですよね。

その通り (^^;

お詫びがてら、ポータブルな方法をもうひとつ。strpbrk() という関数があります。
ある文字列に対して、指定した文字のうちのどれかが含まれているかどうかを判定
する関数です。

使ったソースはこんな感じ。

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

int main()
{
  FILE* f = fopen("m.txt", "r");
  char buf[1024];
  while (fgets(buf, sizeof(buf), f)) {
    if (strpbrk(buf, "0123456789")) {
      fputs(buf, stdout);
    }
  }
  return 0;
}

# 今度は、動作確認済み :-)
    • good
    • 0

やはり普通は isdigit() を使うと思います。



a-kumaさんのコードでよいかと思いますが、

if (! has_digit) {
printf("%s\n", buf);
}

の部分は

if (has_digit) {

ですよね。

また、文字列を fgets() で読み込んでいる場合は '\n' が最後に残っていますので、
printf("%s\n",buf);
とすると '\n' が2回出てきてしまいます。
fputs() だと、最後の '\n' は出力されません。
    • good
    • 0

char buf[256];


char* p;
FILE* is; /* 入力 */
FILE* os; /* 出力 */

while (p = fgets(buf, 255, is)) {
    while (*p && !isdigit(*p))
        p++;
    if (*p)
        fputs(buf, os);
}

アプローチは全く同じで,isdigit を使います.
    • good
    • 0

> 「数字が混じっている」「混じっていない」の判定方法がわかりません。



isdigit() という関数(普通は、マクロ)がありますので、それを使うのが良いでしょう。

int has_digit;
char buf[1024]; /* これに一行の文字列が入る */

/* buf に文字列を入れて */

has_digit = 0;
for (ch = buf ; *ch && ! has_digit ; ++ch) {
has_digit = isdigit(*ch);
}

if (! has_digit) {
printf("%s\n", buf);
}

これを行数分だけループさせれば良いんではないかな?

# 試してません m(_ _)m
    • good
    • 0

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

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

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

Qfgetsでバッファ残留文字列を無視して読み込む

お世話になります。
早速質問させていただきます。

言語はC++です。

ファイルに、以下の文字列があったとします。
============================
123456789012
12345678901
1234567890
123456789
============================
この時、

fgets( str, 10, fp);
printf("str (%2d)= %s\n", strlen(str), str);

を、EOFになるまで繰り返します。

すると、実施結果は
============================
123456789
012

123456789
01

123456789
0

123456789
============================
となります。

これは、fgetsで10というレングスを指定しているために、1行読み込んで、10文字以降の文字列はバッファに残ってしまっているため、
2度目のfgetsで、10文字以降の文字列が読み込まれ、書き出されているものと思われます。

この時、fgetsで1行読み込んだ後、バッファに残った文字列を無視し、2度目のfgetsで、2行目を読み込むにはどうしたらよいでしょうか?

有識者の方、ご教授ください。よろしくお願いします。

お世話になります。
早速質問させていただきます。

言語はC++です。

ファイルに、以下の文字列があったとします。
============================
123456789012
12345678901
1234567890
123456789
============================
この時、

fgets( str, 10, fp);
printf("str (%2d)= %s\n", strlen(str), str);

を、EOFになるまで繰り返します。

すると、実施結果は
============================
123456789
012

123456789
01

123456789
0

123456789
============================
となります。

これは、fge...続きを読む

Aベストアンサー

たぶん、質問にストレートに答えれば「fflush()を使う」になるのだと思います。
もしかしたら、キー入力に限定すればそれでうまくいくかも知れませんが、あまりスマートな方法とは思えません。

結果的に何をしたいのかが不明なので、答えが難しいですが、通常は fgets()で必要量以上のエリア(strの代わりになるもの)に1行まるまる読み込んでから、必要分だけをstrなどに格納するのが入力媒体に依存しない確実な方法となります。

あるいは、strの先頭10文字だけと言うのならば、strに1行読み込んだ後に、
printf("%10.10s\n",str);
と言う手もあると思います。

これはstrの内容をどうしたいのかで、正解は違ってきますが、どちらにしてもfgets()では1行読み込むようにしましょう。

数バイトのメモリーをケチっても、誰も得はしませんので、どんどん使いましょう。

参考URL:http://www9.plala.or.jp/sgwr-t/lib/fflush.html

Qfgetsで読み込んだ値のvector処理

Visual C++ 2008でc++プログラミングの勉強をしています。
ファイルから文字列をfgetsで読み込み、vectorにいれる処理をプログラミングしようとしているのですが、うまくいきません。
input.txt------------------
sumday
monday
tuesday
-------------------------
このような入力ファイルをfgetsで読み込み、各行を文字列としてvectorにpush_backし、 読み込みが終わった後にvectorの全要素をループで出力するというシンプルなものなのですが、以下のようにコーディングしました。


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

int main(void){
using namespace std;
FILE *fp;
fp = fopen("input.txt","r");
std::vector<char *> my_vector;
char buff[16];


while(fgets(buff, 256, fp) != NULL) {
char copy_of_buff[16];
std::strcpy(copy_of_buff, buff);
my_vector.push_back(copy_of_buff);
printf("output from fgets..... %s \n", copy_of_buff);
}

vector<char *>::iterator it = my_vector.begin(); //
while( it != my_vector.end() ) //
{
printf("output from vector.... %s \n", *it);
++it; //
}
fclose(fp);
return 0;
}

以下のような出力がなされるものと思っていたのですが、
outputs from fgets .... sunday
outputs from fgets .... monday
outputs from fgets .... tuesday
output from vector .... sunday
output from vector .... monday
output from vector .... tuesday
実際は以下のように、vectorからの出力分がすべて最後にpush_backした"tuesday"となりました。
outputs from fgets .... sunday
outputs from fgets .... monday
outputs from fgets .... tuesday
output from vector .... tuesday
output from vector .... tuesday
output from vector .... tuesday

fgetsしたあとの処理が問題だと思うのですが、原因がよく分かりません。非常に基本的なことだと思うのですがwebで調べてもいまいちわかりません。
原因が分かる方、よろしくお願いします。

Visual C++ 2008でc++プログラミングの勉強をしています。
ファイルから文字列をfgetsで読み込み、vectorにいれる処理をプログラミングしようとしているのですが、うまくいきません。
input.txt------------------
sumday
monday
tuesday
-------------------------
このような入力ファイルをfgetsで読み込み、各行を文字列としてvectorにpush_backし、 読み込みが終わった後にvectorの全要素をループで出力するというシンプルなものなのですが、以下のようにコーディングしました。


#include <stdio...続きを読む

Aベストアンサー

最初のプログラムは「文字列」ではなく「文字列が入っていた場所の先頭アドレス」をプッシュバックしています。

my_vectorが「char *」つまり「文字列が入っている場所の先頭アドレス」を要素に持つと宣言されているのですから、文字列そのものは入れられません。

「中に入っている文字列は毎回違う」のですが、残念ながら「プッシュバックされた文字列の先頭アドレスは毎回同じ」です。

ループでは「&copy_of_buff[0]」が3回プッシュバックされます。

プッシュバックのループを抜けると「文字列」が破棄されますが「メモリには最後にプッシュバックした時の残骸である、最後の文字列が残って」います。

で、ベクター要素を走査すると、毎回「&copy_of_buff[0]」が取り出されます。

copy_of_buffは既に破棄されているので、取り出したアドレスが差すメモリには、最後にそこに入れた文字列の残骸があります。

そして、表示ルーチンでは、その「残骸」を表示する事になります。

修正したプログラムでは、stringをプッシュバックしているので、string(のコピー)がプッシュバックされます。

my_vectorが「string」つまり「文字列そのもの」を要素に持つと宣言されているのですから、文字列そのものが入れられます。

最初のプログラムの
char copy_of_buff[16];

char *copy_of_buff = malloc(16);
にすれば、とりあえずは動きます。

これが意図した通りに動く理由は「毎回、新しい領域を確保している」「毎回、新しく確保した領域のアドレスをプッシュバックしている」「表示が終るまで確保したメモリを破棄しないで取ってある」からです。

但し、この修正だけでは「確保した領域を使い終わったのに開放してない」ので、不完全です。

++it; //

free(*it++); //
に変えて、表示し終わったら解放しましょう。

最初のプログラムは「文字列」ではなく「文字列が入っていた場所の先頭アドレス」をプッシュバックしています。

my_vectorが「char *」つまり「文字列が入っている場所の先頭アドレス」を要素に持つと宣言されているのですから、文字列そのものは入れられません。

「中に入っている文字列は毎回違う」のですが、残念ながら「プッシュバックされた文字列の先頭アドレスは毎回同じ」です。

ループでは「&copy_of_buff[0]」が3回プッシュバックされます。

プッシュバックのループを抜けると「文字列」が...続きを読む

Qfgetsでcsvファイルを読み込めなくなる!?

fgetsでcsvファイルを読み込めなくなる!?

Cを使って、csvをfgetsで読み込むプログラムを作っています。
実際に製作し、csvファイルを(A.csvとします)読み込むことができました。

しかしデスクトップ上で
「新規作成」
→「txtファイルを作成」
→「拡張子を.csvにし、csvファイル(B.csv)を作成」
→「Aの中身をコピーし、Bにペースト」
を行い、B.csvを読み込もうとすると、
読み込むことができません(正確には文字化けした、単語が数文字表示される)

これは何が原因なのでしょうか?
ご教授お願いいたします。

Aベストアンサー

『fgets()で読み込む』ということなので、プログラムで使用している文字コードはShiftJISでしょう。

csvファイルを何を使って編集しているかわかりませんが、
Windows標準のメモ帳で編集してみてはどうですか?

「ファイル」「名前を付けて保存」を選択すると表示されるダイアログボックスに、
[文字コード]を選択する欄が表示されます。
ここで「ANSI」を選択(XPの場合)して保存すれば、ShiftJISで保存されます。

Qファイルから数字列を16進数の数字列として読み込むためには?

C言語初心者です。
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef…
0135792468acebdf0135792468acebdf0135792468acebdf0135792468acebdf…

のようなファイルがあったときに、このファイルを自分で用意した配列num[]に1次元配列形式、かつ16進数で読み込むコードが思いつかず困っています。ファイルは複数行かつ複数列存在し、各行と各列はそれぞれ長さはマチマチとします。
つまり、例えば
1234abcdf
2315a
cedf45
のようなファイルをnum[20]という配列に格納したいのです。

この場合、fgetc, fgets, fscanf等、使える関数は数種類あると思うのですが、どの方法がもっとも効率的に、かつ高速に自分が用意した配列numに読み込めるのでしょうか?

また、メモリ量もできるだけ節約したいので、同状況でmalloc等で読み込んだファイルの文字数のみの要素数を確保するやり方も考えているのですが、これも思いつかずに困っています(つまり、num[10000]とかをやるのは避けたいということです)

C言語に堪能な方がおられましたらご教授下さい。具体的なソースで説明していただけると助かります。

C言語初心者です。
0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef…
0135792468acebdf0135792468acebdf0135792468acebdf0135792468acebdf…

のようなファイルがあったときに、このファイルを自分で用意した配列num[]に1次元配列形式、かつ16進数で読み込むコードが思いつかず困っています。ファイルは複数行かつ複数列存在し、各行と各列はそれぞれ長さはマチマチとします。
つまり、例えば
1234abcdf
2315a
cedf45
のようなファイルをnum[20]という配列に格納したいのです。

こ...続きを読む

Aベストアンサー

こんにちは。

#3の方が書かれているように、
C言語でファイルサイズを取得する方法はいくつかあると思います。

◎参考サイト
C言語 ファイル位置の取得 ファイルサイズの取得
http://simd.jugem.jp/?eid=57

fseek、および ftell によるファイルサイズを求める方法を用いて、今回の案件の処理を行う
サンプルプログラムを作ってみました。(下記参照)
ファイル読込みには、fgets を使用しています。
なお、今回のサンプルで扱えるファイルのファイルサイズ上限は、2GByteまでとなります。

注)間違っている点があるかもしれませんので、あくまで参考程度として下さい。

■サンプルプログラム

実行の際は、コマンドライン引数に、入力ファイル名(16進文字列が記述されたテキストファイル
のファイル名)を指定して実行して下さい。

注)以下のソースには、インデント(字下げ)のため、全角スペースが入っています。
  コンパイルの際は、半角スペースorタブへ置換するか削除して下さい。

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

/* define const */
#define MAXBUF 256

/* prototype */
int ConvHex2Bin( char cHex, unsigned char *cBin );
void DumpBinBuf( unsigned char *pBinBuf, long nBinLen );

/*
* main
*/
int main( int argc, char *argv[] )
{
  char *psFileName;
  FILE *fpInp;
  int ists;
  int ierr;
  int i, len;
  long nGetSize;
  long nPos, nBinLen;
  char cch;
  unsigned char bch;
  unsigned char *pBinBuf;
  char strLine[MAXBUF+1];

  //コマンドラインのチェック
  if(argc < 2){
    printf( "## Command Line Error!! (Not File Name)\n");
    return -1;
  }
  psFileName = argv[1];

  //入力ファイル名の表示
  printf( "Input File Name: \"%s\"\n", psFileName );

  //入力ファイルオープン
  if((fpInp = fopen( psFileName, "rb" )) == NULL){
    printf( "## File Open Error!!\n" );
    return 1;
  }

  //入力ファイルのサイズを取得
  //※ファイル末尾へシークしてファイルポジションを取得
  ists = fseek( fpInp, 0L, SEEK_END );
  if(ists){
    printf( "## File Seek Error (SEEK_END)!!\n" );
    fclose( fpInp );
    return 2;
  }
  nGetSize = ftell( fpInp );
  if( nGetSize == -1L ){
    printf( "## File Point Error ! (ftell)!\n" );
    fclose( fpInp );
    return 3;
  }

  //入力ファイルのサイズ表示
  printf( "Input File Size: %ld (byte)\n", nGetSize );

  //ファイルポジションを先頭に移動
  ists = fseek( fpInp, 0L, SEEK_SET );
  if(ists){
    printf( "## File Seek Error!! (SEEK_SET)\n" );
    fclose( fpInp );
    return 2;
  }

  //バイナリバッファのメモリ確保
  pBinBuf = (unsigned char *)malloc( nGetSize );
  if(pBinBuf == NULL){
    printf( "## Memory Allocate Error!!\n" ) ;
    fclose( fpInp );
    return 4;
  }

  //ファイル読込み&バイナリバッファへ格納
  nPos = 0;
  ierr = 0;
  while( fgets( strLine, MAXBUF, fpInp ) != NULL )  //1行読込み
  {
    //1行毎に読込んでバイナリバッファへ格納
    len = strlen( strLine );
    for( i=0; i<len; i++ )
    {
      cch = strLine[i];
      if(cch != '\r' && cch != '\n'){      //改行文字以外?
        ists = ConvHex2Bin( cch, &bch );  //HEX文字→バイナリ値変換
        if(ists == 0){
          pBinBuf[nPos++] = bch;      //バイナリバッファへセット
        }
        else {
          ierr = 1;
          break;    //エラーならループを抜ける
        }
      }
    }
    if(ierr) break;    //エラーならループを抜ける
  }
  nBinLen = nPos;    //読込んだデータ長を取得

  //ファイルクローズ
  fclose( fpInp );

  //16進文字以外が有った場合のエラー表示
  if(ierr){
    printf( "## File format Error!!\n" );
    if(pBinBuf != NULL){
      free( pBinBuf );
      pBinBuf = NULL;
    }
    return 5;
  }

  //バイナリデータのデータ長を表示
  printf( "Bin data Length: %ld (byte)\n", nBinLen );

  //バイナリデータのダンプ
  printf( "** Binary data Dump **\n" );
  DumpBinBuf( pBinBuf, nBinLen );

  //確保したメモリの解放
  if(pBinBuf != NULL){
    free( pBinBuf );
    pBinBuf = NULL;
  }

  return 0;
}

/*
* ConvHex2Bin : HEX文字→バイナリ値変換
*/
int ConvHex2Bin( char cHex, unsigned char *cBin )
{
  *cBin = 0;

  if(cHex >= '0' && cHex <= '9'){
    *cBin = cHex - '0';
  }
  else if(cHex >= 'a' && cHex <= 'f'){
    *cBin = cHex - 'a' + 10;
  }
  else if(cHex >= 'A' && cHex <= 'F'){
    *cBin = cHex - 'A' + 10;
  }
  else {
    *cBin = '.';
    return -1;
  }

  return 0;
}

/*
* DumpBinBuf : バイナリデータのダンプ
*/
void DumpBinBuf( unsigned char *pBinBuf, long nBinLen )
{
  long nPos;
  unsigned char bch;

  printf("Address : +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F\n");

  for(nPos=0; nPos<nBinLen; nPos++)
  {
    if((nPos % 16L) == 0){
      printf("%08lx:", nPos);
    }

    bch = pBinBuf[nPos];
    if(bch >= 0 && bch < 16){
      printf(" %1x", bch);
    }
    else {
      printf(" .");
    }

    if( (nPos+1) == nBinLen || ((nPos+1) % 16L) == 0 ){
      printf("\n");
    }
  }
}
---------------------------------------------------------

■プログラムの実行例
◎入力ファイル("test.txt")が下記内容だった場合
1234abcdf
2315a
cedf45

◎実行結果
Input File Name: "test.txt"
Input File Size: 26 (byte)
Bin data Length: 20 (byte)
** Binary data Dump **
Address : +0 +1 +2 +3 +4 +5 +6 +7 +8 +9 +A +B +C +D +E +F
00000000: 1 2 3 4 a b c d f 2 3 1 5 a c e
00000010: d f 4 5

こんにちは。

#3の方が書かれているように、
C言語でファイルサイズを取得する方法はいくつかあると思います。

◎参考サイト
C言語 ファイル位置の取得 ファイルサイズの取得
http://simd.jugem.jp/?eid=57

fseek、および ftell によるファイルサイズを求める方法を用いて、今回の案件の処理を行う
サンプルプログラムを作ってみました。(下記参照)
ファイル読込みには、fgets を使用しています。
なお、今回のサンプルで扱えるファイルのファイルサイズ上限は、2GByteまでとなります。

注)...続きを読む

Qfgetsで配列に数字を入れる。

C言語についての質問です。
配列の中にひとつずつ数字を入れたいと思っています。
char suuzi[16];
fgets(suuzi, sizeof(suuzi), stdin);

のような感じで読み込ませてるのですが、数字で読み込まれず文字として読み込まれてるみたいです。
数字として配列にひとつずついれるにはどのようにしたらよいかどなたか教えてください。

Aベストアンサー

16桁の数を要素数16の配列に1つずつ入れたい、と言うことでしょうか?
ループでgetc()を回しながら数値化したらいいんじゃないかなぁ、と言うわけでやっつけですがこんな感じではどうでしょう?

int i, c;
char suuzi[16];

for (i = 0; i < 16; i++)
{
c = getc(stdin);
suuzi[i] = (char)(c - '0');
}


文字の「0」(0x30) を引くことで数値化してます。
# fgetsで取得したあとにatoiとかで数値化しても良いですが、1文字単位ならこっちの方が楽かな、と思った次第です。

なお、入れ物のsuuzi[16]はcharのままにしてありますが、支障がなければintにした方が何かと都合が良いかもしれません。


人気Q&Aランキング

おすすめ情報