ページ 1 / 1
複数あるファイル内の重複を探す方法
Posted: 2010年6月17日(木) 11:10
by トマト
ファイルの内にある文字列をgrepするような操作をさせたい
最終的には、複数のファイル内という拡張させてたいのです。
どうしたらいいのか、ご教授頂けると幸いです。
現在は、引数でファイルを指定してそのファイルの中身を表示させる部分を構築しましたが
配列に格納して検索させるようにしたいのですが
それすらできずにいます。
/* ファイルの中身表示 */
if((fp = fopen( *argv, "rb" )) == NULL)
{
printf("can not open file. %s\n", *argv);
return -2;
}
printf("file open success\n");
size = fread( buff, sizeof(char), STRING_MAX, fp);
if(size == 0)
{
printf("Can not Open FILE\n");
fclose(fp);
return -3;
}
for(count=0; count<size; count++)
{
printf("count[%d],%s\n", count,buff);
}
buff内にデータが格納されているのでしょうか?
どうしたら重複検索して一つだけ残すようにできるのでしょうか?
どうかよろしくお願いします。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月17日(木) 13:47
by トマト
補足で追記します。上記のプログラムの出力結果は以下のようになっていました
count[0],2010/05/02
00:00
iso.3.6.1.2.1.4.22.1.2.9 192.168.0.1 = Hex-STRING: 00 00 00 00 QQ AH
iso.3.6.1.2.1.4.22.1.2.9.143.125.64.93 = Hex-STRING: 00 00 00 43 ZZ 80
2010/05/02
12:00
iso.3.6.1.2.1.4.22.1.2.9.143.125.64.92 = Hex-STRING: 00 00 00 AA B1 55
iso.3.6.1.2.1.4.22.1.2.9.143.125.64.93 = Hex-STRING: 00 00 00 5A X9 AB
count[1],2010/05/02
00:00
配列[0] と配列[6]を比較する等の検索をしたいと思っております。
どうか知識をお借りできないでしょうか?
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月17日(木) 19:37
by ookami
はじめに、意地悪を言うつもりではないことを断っておきます。
> 文字列をgrepする
> 配列に格納して検索させる
> buff内にデータが格納されているのでしょうか?
> 重複検索して一つだけ残す
> 配列[0]と配列[6]を比較する
このあたりについて、もうちょっと説明を補足してもらえませんか?いまいち意味がわかりません。
あと、開発環境などもお願いします。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 09:20
by トマト
分かりにくくて、すみませんでした。
開発環境は CentOS 5.2(Linux), C言語で書いています。
1つのファイルの中に、
iso.3.6.1.2.1.4.22.1.2.9 192.168.0.1 = Hex-STRING: 00 00 00 00 QQ AH
のような文字列が20行くらいあるもの、5行しかないもの等バラバラで
ファイルの中には「192.168.0.1」と「00 00 00 00 QQ AH」のペアが重複して
混ざっているものがあります。
それを探すプログラムを作りたくて相談させていただきました。
重複があった場合は一つ消します。(重複箇所をなくす)
ファイル総数は30くらいです。
その30ファイルの中から重複箇所をなくすプログラムを作成したいです。
現在は以下にしてみました。(引数で検索したいファイルを指定)
if((fp = fopen( *argv, "rb" )) == NULL)
{
printf("can not open file. %s\n", *argv);
return -2;
}
size = fread( buff, sizeof(char), STRING_MAX, fp);
if(size == 0)
{
printf("Can not Open FILE\n");
fclose(fp);
return -3;
}
for(i=0;i<size; i++)
{
strcpy(data,buff);
}
fscanf(fp,"\n");
fclose(fp);
まだまだ、分かりにくい点あると思います。指摘してくだされば直します。
どうかよろしくお願いします。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 10:23
by シエル
>重複があった場合は一つ消します。(重複箇所をなくす)
この意味は重複してる行をファイルから直接削除したいということでしょうか?
それと変数の宣言やmain関数などが含まれるコードをすべて貼っていただけますか?
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 10:23
by へろりくしょん
具体的な事はさっぱりわかりませんが、やりたいことは何となく解りました。
とりあえず、ハッシュテーブルでも作ってテーブルの要素をリストで繋いで行けばいいんじゃないですか?
「192.168.0.1」と「00 00 00 00 QQ AH」をそれぞれ1つの語として扱うのなら、それをどんどん放り込んで行って、コリジョンを起こせば重複していることが解りますね。
で、コリジョンを起こさなければ、ファイルに書き込み、起こせばスルー。
それで出来ると思います。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 11:16
by トマト
>重複してる行をファイルから直接削除したいということでしょうか?
->その通りです!
>それと変数の宣言やmain関数などが含まれるコードをすべて貼っていただけますか?
引数で指定されたファイルを配列にコピーしてみました。
(配列に入っているか自信はないですが・・・)
#define STRING_MAX 10000
#define ARP_INFO 2048
int main(int argc, char **argv)
{
FILE *fp;
//unsigned char buf[STRING_MAX];
char buff[STRING_MAX];
//char arpinfo[STRING_MAX];
int i, j, count;
int chk;
size_t size;
char data[ARP_INFO];
if(argc < 2)
{
printf("Usage : XTYPE filename1 [filename2 ...]\n");
return -1;
}
while(--argc)
{
++argv;
if((fp = fopen( *argv, "rb" )) == NULL)
{
printf("can not open file. %s\n", *argv);
return -2;
}
size = fread( buff, sizeof(char), STRING_MAX, fp);
if(size == 0)
{
printf("Can not Open FILE\n");
fclose(fp);
return -3;
}
for(i=0;i<size; i++)
{
strcpy(data,buff);
}
fscanf(fp,"\n");
fclose(fp);
}
return 0;
}
ハッシュは考えていませんでした!
取りあえず
配列[0]とマッチするのは配列[x]はある?
配列[1]とマッチするのは配列[x]はある?
配列[2]とマッチするのは配列[x]はある?
と、検索をしようとしていました。
いい方法ありましたら教えてください。
申し訳ありませんが、知識不足でハッシュテーブルのやり方をする場合のコードも
どのようにするのかさえ分かっていません。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 11:50
by ookami
まだいまいち分からないのですが、とりあえずハッシュの話が出たので、以下が参考になるでしょうか?
http://oshiete.homes.jp/qa3257451.html
あと、
> buff内にデータが格納されているのでしょうか?
> (配列に入っているか自信はないですが・・・)
このような場合はprintfか何かで画面に出力すれば確認できると思います。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 12:14
by へろりくしょん
やっぱり今ひとつ不明瞭です。
>引数で指定されたファイルを配列にコピーしてみました。
この配列というのは char buff[STRING_MAX]; の事ですよね。
>配列[0]とマッチするのは配列[x]はある?
>配列[1]とマッチするのは配列[x]はある?
>配列[2]とマッチするのは配列[x]はある?
の、配列というのも char buff[STRING_MAX]; の事ですよね。
この配列にはファイルの中身のバイト列が納められていますので、buf[x]には、
改行コード等を含めファイルの先頭からxバイト目が1バイト納められています。
上記の文の、"配列[0]とマッチするのは配列[x]はある? "というのは、
0バイト目とxバイト目の文字を比較するのだと解釈できますがいかがでしょう。
おそらく、トマトさんが要求する仕様とは違いますよね?
比較の対象となる語が不明瞭です。
あまり1度に考えず1つ1つ丁寧にやって行けばそんなに難しいことはないと思いますよ。
手順としては、
1.ファイルを開く。
2.1行読み込む。
3.必要な語を切り出す。
4.どっかに覚えさせておく。
この時に比較します。 もしすでに覚えている語だったら重複しています。
で、まだ覚えていない語だった場合のみ、別のファイルに書き出すようにします。
5.ビールを飲む。
これらを1つ1つ関数化すれば、より見通しがよくなるわかりやすくなると思います。
ハッシュテーブルはただの配列ですよ。
ハッシュのコリジョン対策として、各要素をリスト構造で実装しましょうねというだけの事です。
ですから、構造体のポインタの配列ということになりますね。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 12:19
by へろりくしょん
私がここで言うハッシュというのは、Perlで言うところの連想配列ではなく、もっと広い意味でのハッシュです。
アルゴリズムの解説はここに詳しく。
http://www.geocities.jp/ky_webid/algorithm/014.html
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 13:14
by トマト
>0バイト目とxバイト目の文字を比較するのだと解釈できますがいかがでしょう。
>おそらく、トマトさんが要求する仕様とは違いますよね?
そうです。違いますね。行単位での比較で行いたいです。
1つのファイルの中身は以下のようになっています。
iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10
iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.11 = Hex-STRING: 00 00 00 CB 12 CC
iso.3.2.1.2.1.4.11.0.2.1062.192.169.62.1 = Hex-STRING: 00 00 00 0A 58 2E
iso.3.2.1.2.1.4.11.0.2.1062.192.169.62.12 = Hex-STRING: 00 00 00 AB 1E DF
(以下40行くらい続く・・・)
を以下のようにしました
配列[0]iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10
配列[1]iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.11 = Hex-STRING: 00 00 00 CB 12 CC
配列[2]iso.3.2.1.2.1.4.11.0.2.1062.192.169.62.1 = Hex-STRING: 00 00 00 0A 58 2E
配列[3]iso.3.2.1.2.1.4.11.0.2.1062.192.169.62.12 = Hex-STRING: 00 00 00 AB 1E DF
char buff[STRING_MAX] の中身↑
printf()で表示させた結果で確認しました。
そのchar buff[STRING_MAX]で
配列[0] の [192.169.61.1] と [00 00 00 00 66 10]の組み合わせ
配列[1] の [192.169.61.11] と [00 00 00 CB 12 CC]の組み合わせ
配列[2] の [192.169.62.1] と [00 00 00 0A 58 2E]の組み合わせ
配列[3] の [192.169.62.12] と [00 00 00 AB 1E DF]の組み合わせ
比較したい文字を明確にする。
配列[0] と 配列[1] は同じもの?
配列[0] と 配列[2] は同じもの?
配列[0] と 配列[3] は同じもの?
配列[0] と 配列[4] は同じもの?
もし、配列[0] と 配列[1] は同じものならば配列[0]だけにしたい
重複箇所を取り除いたものを別ファイルにて保存。
ファイル総数は30前後。その30あるファイルには最終的に重複箇所は「なし」とする。
>1つ1つ関数化すれば、より見通しがよくなるわかりやすくなると思います。
ありがとうございます。まずは、一つづつ関数化してみます。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 16:54
by トマト
アドバイスをください
>1.ファイルを開く。
>2.1行読み込む。
>3.必要な語を切り出す。
char *substr(char *buffer, const char *string, int start, int stop)
{
memmove(buffer, string + start, stop - start);
buffer[stop - start]= '\0';
return 0;
}
上記のような関数を利用し
>3.必要な語を切り出す。をしています。
substr(mojiIP, data, 45, 59);/* IP ADDRESS */
substr(mojiMAC, data, 74, 93); /* MAC ADDRESS */
/* 文字列の連結 */
strcat(mojiIP, ",");
strcat(mojiIP, mojiMAC);
(192.169.61.1,00 00 00 00 66 10が取り出せる)
これでは、以前に指摘いただいた
>0バイト目とxバイト目の文字を比較する
になってしまい、
今回やりたい
配列[0]iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10
配列[1]iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.11 = Hex-STRING: 00 00 00 CB 12 CC
の比較ができなくなってしまいました。
どのようにすれば比較できるようになれるのでしょうか?
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 17:58
by シエル
バイナリモードで読み込むと改行をうまく読めないので、
テキストモードで読みこむようにし、下記のようなコードを書いてみました。
一応、「192.168.0.1」と「00 00 00 00 QQ AH」のペアがファイル内に重複していた場合、
「192.168.0.1」と「00 00 00 00 QQ AH」のペアを一回だけファイルに書きだし、
その他の文字列は順番にすべて書きだすようにしています。
コンパイル後、実行ファイルに該当のファイルをドラッグすると、重複を除いたtesttmp.txtが
作成されるようにしています。
イメージと違うかもしれませんが、参考になれば幸いです。
#include <stdio.h>
#include <string.h>
int main(int argc,char *argv[/url])
{
char s1[/url]="192.168.0.1";
char s2[/url]="00 00 00 00 QQ AH";
char tmp[1024];
int flag=0;
FILE *fp,*fp2;
if(argv[1]==NULL)
return -1;
fp2=fopen("testtmp.txt","w");
fp=fopen(argv[1],"r");
if(fp==NULL){
printf("ファイルオープン失敗");
return -1;
}
while(fgets(tmp,sizeof(tmp),fp)){
if(strstr(tmp,s1)){
if(strstr(tmp,s2)){
if(flag==0){
fprintf(fp2,"%s",tmp);
flag=1;
}
}else{
fprintf(fp2,"%s",tmp);
}
}else{
fprintf(fp2,"%s",tmp);
}
}
fclose(fp);
fclose(fp2);
return 0;
}
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月18日(金) 18:40
by Poco
> 重複箇所を取り除いたものを別ファイルにて保存。
> ファイル総数は30前後。その30あるファイルには最終的に重複箇所は「なし」とする。
ここをもっと明確にしませんか?
処理後のファイル数は処理前と変わらないんですよね?
では、2つのファイルAとBに重複rが見つかったとして、どっちのrが消えるのですか?
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月19日(土) 08:40
by へろりくしょん
>>3.必要な語を切り出す。をしています。
>substr(mojiIP, data, 45, 59);/* IP ADDRESS */
>substr(mojiMAC, data, 74, 93); /* MAC ADDRESS */
>/* 文字列の連結 */
>strcat(mojiIP, ",");
>strcat(mojiIP, mojiMAC);
>(192.169.61.1,00 00 00 00 66 10が取り出せる)
ちょっと言い方が悪かったようです。
私の言う必要な語というのは、検索に必要な最終的な語のことです。
"192.169.61.1,00 00 00 00 66 10"が取り出せるというのは、上で切り出した2つの文字列を1セットに、それが重複していないかを調べるのですか?
私はてっきり"iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10 "という文字列が重複していないかを調べるのだと思っていましたが、どっちなんでしょう?
>これでは、以前に指摘いただいた
>>0バイト目とxバイト目の文字を比較する
>になってしまい、
>今回やりたい
>配列[0]iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10
>配列[1]iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.11 = Hex-STRING: 00 00 00 CB 12 CC
>の比較ができなくなってしまいました。
>どのようにすれば比較できるようになれるのでしょうか?
"iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10"自体がすでに文字の配列ですので、この文字の配列をさらに配列に納めるのならば、配列の配列を利用する必要があります。
ざくっと外枠だけ書いておきます。
#define LINE_MAX 1024 //1行あたりの最大文字数
static char **table = NULL; //テーブル
static int tblSize = 0; //テーブルのサイズ(利用可能サイズ)
static int useSize = 0; //テーブルの使用済みサイズ
int AddString(const char *buf)
{
int i;
//テーブルから検索して、すでに覚えていれば1を返す。
for(i = 0;i<useSize;i++){
if(!strcmp(table, buf)) return 1;
}
//テーブルに覚えさせる。
if(useSize >= tblSize){
tblSize += 100;
table = realloc(table, sizeof(char**) * tblSize);
}
table[useSize] = malloc(LINE_MAX);
strcpy(table[useSize], buf);
useSize++;
return 0;
}
main()
{
while(--argc){
FILE *fr, *fw;
char line[LINE_MAX];
fr = fopen(); //読み込みファイルのオープン
fw = fopen(); //書き込みファイルのオープン
//1行ずつ読み込む
while(fgets(line, LINE_MAX, fr)){
char *word;
//語の切り出し
word = substr(line);
//テーブルへ追加
if(AddString(word)) continue; //重複してたらとっとと次の行
//ファイルへ書き込み
fprintf();
}
fclose(fr);
fclose(fw);
}
return 0;
}
こーんな感じでいいかと。
テーブルは語の数に応じてニョキニョキと伸長させてます。
単純な線形探索です。
見ての通りコンパイルは通りませんのでしてません。
変数名なんかのタイプミスはないと思います。 あったらごめんなさい。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月19日(土) 11:45
by トマト
iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10 "という文字列が重複していないかを調べる
が、やりたいことです。
> 重複箇所を取り除いたものを別ファイルにて保存。
> ファイル総数は30前後。その30あるファイルには最終的に重複箇所は「なし」とする。
①どちらか一方だけが消えれば良いです。
②ファイル内の重複を消す。
ひとつのファイルの中身
検索-> 重複箇所発見-> ひとつにする
上記のような事をしたいファイルは30前後ある。
ファイルは、
4/10 いくつマシンがネットワークにあるか(IPアドレス&MACアドレス情報)
4/11 いくつマシンがネットワークにあるか(IPアドレス&MACアドレス情報)
4/12 いくつマシンがネットワークにあるか(IPアドレス&MACアドレス情報)
重複は必然と出てきてしまう。
コードありがとうございます!
さっそく作成してみます。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月19日(土) 21:44
by Poco
もう1点確認させてください。
プログラム作らなきゃ駄目ですか?
UNIX系のコマンド組み合わせるだけで行ける気がするんですが。。
grep 'iso.3.' *| sort -u > result.txt
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月21日(月) 13:11
by トマト
>grep 'iso.3.' *| sort -u > result.txt
このコマンド、初めて知りました。まさに「やりたい事」です!
ファイル数が多くて、その度にコマンドを入力しないといけないのを避けたいので
プログラムを組もうとしておりました。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月21日(月) 16:56
by トマト
へろりさんが 教えて下さった方法でさらに質問です。
static char **table = NULL;
int AddString(const char *buf)
{
int i; //テーブルから検索して、すでに覚えていれば1を返す。
for(i = 0;i<useSize;i++){ if(!strcmp(table, buf)) return 1;
}
//テーブルに覚えさせる。
if(useSize >= tblSize){
tblSize += 100;
table = realloc(table, sizeof(char**) * tblSize);
}
table[useSize] = malloc(LINE_MAX);
strcpy(table[useSize], buf);
useSize++;
return 0;
}
error: invalid conversion from ‘void*’ to ‘char*’になってしまいまして、
メモリの割り当ては単純にmallocだけではダメなものなのでしょうか?
恥ずかしい事に、よく理解ができなくてなってしまいました。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月21日(月) 18:54
by シエル
malloc(LINE_MAX)
↑これだけで、動的に確保できるんですかね?
型とか指定しなくていいのでしょうか?あまり詳しくないので分かりませんが。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月21日(月) 19:08
by Poco
> >>
> このコマンド、初めて知りました。まさに「やりたい事」です!
>
> ファイル数が多くて、その度にコマンドを入力しないといけないのを避けたいので
> プログラムを組もうとしておりました。
シェルスクリプト組んでください。
以下サンプルです(動作確認してません)。
----sample.sh----
#!/bin/bash
for i in *
do
grep 'iso.3.' $i| sort -u > $i_result.txt
done
----sample.sh----
実行すのも面倒ならcronでデイリーに実行すればOKです。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 09:01
by トマト
シエルさんが教えて下さった方法で、配列に検索文字を格納させている方法で、
検索文字対象文字が可変な場合にはできませんでした。
ハッシュテーブルを考えていく方向で変更してみます。
メモリ確保で、reallocでメモリの割り当てを変更して、mallocでメモリを確保しないと
ダメなのでしょうけど、
コンパイルエラーが取れなかったのでreallocを行わずにメモリ確保させてしまってます。
>シェルスクリプト組んでください。
サンプルまで、本当にありがとうございます!
ですがこのままのLinux環境からWindowsに以降させなければならないので
プログラムを作成しています。
windowsの移植環境はVC++2010です。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 09:31
by シエル
>ファイルの中には「192.168.0.1」と「00 00 00 00 QQ AH」のペアが重複して
>混ざっているものがあります。
このようにおっしゃっていたので、このペアのやつだけ重複してるやつを
除けばいいと思ってました。すいません。。
時間があったら考えてみます。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 10:00
by へろりくしょん
>error: invalid conversion from ‘void*’ to ‘char*’になってしまいまして、
>メモリの割り当ては単純にmallocだけではダメなものなのでしょうか?
すみません、C言語の話だと勝手に勘違いしていました。
C++では、void*型から、他のポインタ型へキャストする場合は、明示的なキャストを行わない場合エラーとなります。
ので、キャストしてください。
>malloc(LINE_MAX)
>↑これだけで、動的に確保できるんですかね?
>型とか指定しなくていいのでしょうか?あまり詳しくないので分かりませんが。
型を指定と言うのがよくわかりませんが。malloc()関数の戻り値はvoid*型です。
プロトタイプは次のようになっています。
void* malloc(size_t size);
引数は1個で、確保したいバイト数を指定します。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 10:47
by トマト
static char **table = NULL;
table = realloc(table, sizeof(char**) * tblSize);
table[useSize] = malloc(LINE_MAX);
へろり さんが作ってくださったコードで、上記の部分があり
このままではコンパイルエラーでしたので、以下のようにキャストしました。
table[useSize] = (char *)malloc(LINE_MAX);
同じようにrealloc()も 戻り値はvoid*型でしたが以下のようにしました
table = realloc((char *)table, sizeof(char**) * tblSize);
コンパイルしてみると
error: invalid conversion from ‘void*’ to ‘char**’
で、キャストできていなかったので、メモリの割り当てをおこなわなくてもダメでしょうか?
と質問させていただきました。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 11:15
by へろりくしょん
>同じようにrealloc()も 戻り値はvoid*型でしたが以下のようにしました
>table = realloc((char *)table, sizeof(char**) * tblSize);
>コンパイルしてみると
>error: invalid conversion from ‘void*’ to ‘char**’
>で、キャストできていなかったので、メモリの割り当てをおこなわなくてもダメでしょうか?
>と質問させていただきました。
メモリの確保は必ず行うようにしてください。
char **table; はNULLで初期化されていますから、table[useSize] = malloc(LINE_MAX);のコードで落ちます。
キャストが必要なのはvoid*型から、具体的なポインタ型へ変換する場合です。
realloc() 関数の戻り値はvoid*型ですから、これを他のポインタ型へ変換する場合にキャストが必要となります。
ですから、上記のコードは次のようになります。
table = (char**)realloc(table, sizeof(char**) * tblSize);
ちなみにこの変数 table は char** 型です。
ついでに言うと、このテーブルにはハッシュは使っていませんよ。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 11:48
by トマト
大変申し訳ないですが質問させてください
//1行ずつ読み込む
while(fgets(line, LINE_MAX, fr)){
//語の切り出し
word = substr(line);
//テーブルへ追加 if(AddString(word)) continue; //重複してたらとっとと次の行
error: ‘substr’ was not declared in this scope
の上記エラーがでてしまいましたのでstrcpy(word,line); と置き換えは可能でしょうか?
substrをしようする際に
#include <iostream>
#include <string> と using namespace std;を入れ str.substr
と使用する例のものがあったのですが
コンパイルエラーがとれませんでした。ですので、strcpyで逃げて見てるのですが
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 12:02
by へろりくしょん
> error: ‘substr’ was not declared in this scope
> の上記エラーがでてしまいましたのでstrcpy(word,line); と置き換えは可能でしょうか?
>
テキスト文書の1行を1語として扱うのならば、可能です。
fgets()関数は1行を読み出しますから、この時にすでに語の切り出しは完了していると見なせます。
また、その場合はwordは必要ありません。 AddString(line); として大丈夫です。
> substrをしようする際に
> #include <iostream>
> #include <string> と using namespace std;を入れ str.substr
> と使用する例のものがあったのですが
> コンパイルエラーがとれませんでした。ですので、strcpyで逃げて見てるのですが
>
正直C++はさっっぱり解りませんのでここはスルーしますが、上記のエラーは単にプロトタイプ宣言が見つからないってだけの事だと思いますよ。
せっかくコンパイラがいろいろと教えてくれてるのですから、エラーが出たから代替手段を探すのではなく、どうしたら解決出来るのかもっとじっくりと考えてみることをおすすめします。
コンパイラが何を言ってるのか解らなければ、コンパイラの言った事をそのままグーグル先生に聞けば大抵の事は解りますから。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 14:37
by トマト
ありがとうございました。何とか動くようになりました。
ですが、読み込んだファイルをそのまま別ファイルに書き出しているようになってしまいました
grep 'iso.3.' (ファイル名)| sort -u > $find.txt
で表示される結果と違うのですが
どこをなおしたらいいのか分からなくなっています。
教えて頂けないでしょうか?
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月22日(火) 21:00
by へろりくしょん
> ありがとうございました。何とか動くようになりました。
> ですが、読み込んだファイルをそのまま別ファイルに書き出しているようになってしまいました
>
書き出したファイルの中で重複が存在するということでしょうか。
> grep 'iso.3.' (ファイル名)| sort -u > $find.txt
> で表示される結果と違うのですが
>
存在する行のすべてを対象としていますから、iso.3.6.1.2.1.4.22.1.2.9 192.....といったデータだけで無く、日付や時間といった行も対象としています。
iso.から始まる行だけを切り出したい場合は、strncmp()関数あたりで場分けしてください。
また、ソートは行ってませんので、検索して見つかった行を見つかった順番に頭から出力します。
> どこをなおしたらいいのか分からなくなっています。
> 教えて頂けないでしょうか?
書いたコードを提示してください。
ついでに、重複が存在する入力ファイルの中身と、どのような結果になって欲しいのか期待する出力結果を提示してください。
今ひとつ仕様が固まってません。
将来Windows環境へ移行するために、プログラムが必要ということですが、Cygwinなんて選択肢もありますね。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 00:13
by Poco
> ですがこのままのLinux環境からWindowsに以降させなければならないので
> プログラムを作成しています。
> windowsの移植環境はVC++2010です。
衝撃の新事実。
Windows環境でPowerShellが使えるなら、やはりワンライナーで実現できます。
Get-Content hogehoge.log | Sort-Object | Get-Unique
コマンドプロンプトしかない環境でもsortコマンドはあるので、
uniqに該当する部分をWSH+VBS(かJS)で作っちゃえば良いです。
こんな感じで。
http://scripting.cocolog-nifty.com/blog ... -77dd.html
http://d.hatena.ne.jp/janus_wel/20080725/1217089244
#ソースコードを統一したいのはよく判るんですが、この手の処理を
#時間をかけて作り込むのはどうかなと思うんですよね。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 12:08
by トマト
分かりにくくて申し訳ありません。教えてくださっているのに生かしきれず本当に申し訳ないです。
------------------------------------------------------------------
>重複が存在する入力ファイルの中身
2010/04/19
12:00
iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10
iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.11 = Hex-STRING: 00 00 00 CB 12 CC
iso.3.2.1.2.1.4.11.0.2.1062.192.169.9.10 = Hex-STRING: 00 00 00 0A 58 2E
iso.3.2.1.2.1.4.11.0.2.1062.192.169.5.134 = Hex-STRING: 00 00 00 AB 1E DF
2010/04/20
00:00
iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10
iso.3.2.1.2.1.4.11.0.2.1061.192.169.3.122 = Hex-STRING: 00 00 C0 BA 50 DE
iso.3.2.1.2.1.4.11.0.2.1062.192.169.62.1 = Hex-STRING: 00 1B D0 0A 5B 2E
iso.3.2.1.2.1.4.11.0.2.1062.192.169.62.12 = Hex-STRING: 00 00 D3 DD 1E 50
2010/04/20
12:00
iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10
iso.3.2.1.2.1.4.11.0.2.1061.192.169.3.122 = Hex-STRING: 00 00 C0 BA 50 DE
iso.3.2.1.2.1.4.11.0.2.1062.192.169.9.10 = Hex-STRING: 00 00 00 0A 58 2E
iso.3.2.1.2.1.4.11.0.2.1062.192.169.62.12 = Hex-STRING: 00 00 00 AB 1E DF
------------------------------------------------------------------
>どのような結果になって欲しいのか期待する出力結果
iso.3.2.1.2.1.4.11.0.2.1061.192.169.61.1 = Hex-STRING: 00 00 00 00 66 10
iso.3.2.1.2.1.4.11.0.2.1062.192.169.9.10 = Hex-STRING: 00 00 00 0A 58 2E
iso.3.2.1.2.1.4.11.0.2.1061.192.169.3.122 = Hex-STRING: 00 00 C0 BA 50 DE
-------------------------------------------------------------------
>最終的にファイルに保存する形式
192.169.61.1,00 00 00 00 66 10
192.169.9.10,00 00 00 0A 58 2E
192.169.3.122,00 00 C0 BA 50 DE
-------------------------------------------------------------------
>書いたコードを提示
>どのような結果になって欲しいのか期待する出力結果には至っていません。
/* ************************************************ */
/* define */
/* ************************************************ */
#define STRING_MAX 102400
#define ARP_INFO 5120
#define LINE_MAX 1024
/* ************************************************ */
/* global variable */
/* ************************************************** */
static char **table = NULL;
static int tblSize = 0; /* table size(利用可能なサイズ) */
static int useSize = 0; /* table size(使用済みサイズ) */
/* ************************************************ */
/* main */
/* ************************************************ */
int main(int argc, char **argv)
{
FILE *fp;
FILE *fdouble;
FILE *fnotice;
char buff[STRING_MAX];
int i;
int repet;
size_t size;
char data[STRING_MAX];
char show[/url]="iso";
char tmp[STRING_MAX];
char cutIP[STRING_MAX];
char cutMAC[STRING_MAX];
char *juidge;
//int flag=0;
char *wordIP;
char *wordMAC;
if(argc < 2)
{ /* パラメータ数のチェック */
printf("Usage : XTYPE filename1 [filename2 ...]\n");
return -1;
}
while(--argc)
{
++argv;
if((fp = fopen( *argv, "r" )) == NULL)
{
printf("can not open file. %s\n", *argv);
return -2;
}
/* 書き>込みファイルのオープン*/
if((fnotice = fopen("notice.txt", "w"))== NULL)
{
printf("can not write file.\n");
return -3;
}
while(fgets(tmp,sizeof(tmp),fp))
{
juidge = strstr(tmp,show);
if(juidge != NULL)
{
fprintf(fnotice,"%s",juidge);
if(AddString(juidge)) continue;
}
else
{
printf("show=\"iso\" not find.\n");
}
}
}
fclose(fp);
fclose(fdouble);
fclose(fnotice);
return 0;
}
PowerShellは、初めて聞きました。
教えて下さったURLありがとうございます。
さっぱり何してるのか分からないので勉強します。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 12:13
by トマト
すみません。解決マークが付いてしまいました
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 12:22
by ookami
「編集」で、「解決!」チェックをはずすと、一覧でも「解決!」ではなくなるようですよww いま別スレで確認してきましたw
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 12:33
by へろりくしょん
解決されているようですが、もういいのでしょうか?
問題は次の行です。
> juidge = strstr(tmp,show);
>
> if(juidge != NULL)
> {
>
> fprintf(fnotice,"%s",juidge);
>
> if(AddString(juidge)) continue;
> }
juidge が NULL でない場合、つまり tmp に文字列 "iso" が含まれる場合次のfprintf(fnotice, "%s", juidge); で問答無用で出力するようになっています。
そして、その後で、テーブルへ追加して重複判定を行っていますね。
これでは重複もへったくれもありません。
AddString() は重複があれば1を返し、重複が無い場合は0を返します。
ですから、AddString() が0を返した場合のみ、ファイルへ出力するようにしてください。
ついでに、最後の方に fclose(fdouble); と、ありますが。
fdouble は初期化されていませんね。 ここでプログラムが落ちれば、次のfclose(fnotice);が実行されません。
そうすると、うまくファイルに書き込めないかと思われます。
Linux ではどうなっているのか解りませんが。
追記です。
書き出し用のファイルですが、入力ファイル毎に出力ファイルを用意するつもりでループの中でオープンするようにしてましたが、ファイル名は決め打ちされているようですね。
このままでは、ループを回るたびに新しくファイルが作られますから、ループの外へ追い出すか、追加書き込みでオープンするようにしてください。

Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 13:44
by トマト
「解決」マークが今だ外せなくなってます。
AddString()の使い方がよく分かっていません。教えて頂けないでしょうか?
fclose(fdouble); は消し忘れです。すみません。
while(fgets(tmp,sizeof(tmp),fp))
{
juidge = strstr(tmp,show);
if(juidge != NULL)
{
flag = AddString(juidge);
if(flag != 0)
{
fprintf(fnotice,"%s",juidge);
}
else
{
continue;
}
}
else
{
printf("serch=\"iso\" not find.\n");
}
}
総ファイル数が50あります。
最終的に一つのファイルにしないといけないです。->重複なしのファイルが最後に一つにします。

Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 13:54
by へろりくしょん
> if(flag != 0)
> {
> fprintf(fnotice,"%s",juidge);
>
}
条件式が違います。
重複が無い場合、つまりそのデータが初見の場合0を返す訳ですから。
if(flag == 0){
fprintf();
}
とします。
1を返した場合は、すでにテーブルへ記憶しているわけですから何もしません。
もう、全部書いておきます。 動作確認はしてません。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LINE_MAX 1024 //1行あたりの最大文字数
static char **table = NULL; //テーブル
static int tblSize = 0; //テーブルのサイズ(利用可能サイズ)
static int useSize = 0; //テーブルの使用済みサイズ
int AddString(const char *buf)
{
int i;
//テーブルから検索して、すでに覚えていれば1を返す。
for(i = 0;i<useSize;i++){
if(!strcmp(table, buf)) return 1;
}
//テーブルに覚えさせる。
if(useSize >= tblSize){
tblSize += 100;
table = (char**)realloc(table, sizeof(char**) * tblSize);
}
table[useSize] = (char*)malloc(LINE_MAX);
strcpy(table[useSize], buf);
useSize++;
return 0;
}
int main(int argc, char *argv[/url])
{
int i;
FILE *fr, *fw;
char line[LINE_MAX];
if(argc < 2){
printf("Usage : XTYPE filename1 [filename2 ...]\n");
return -1;
}
if(!(fw = fopen("notice.txt", "w"))){
printf("can not write file.\n");
return -3;
}
while(--argc){
++argv;
if(!(fr = fopen(*argv, "r"))){
printf("can not open file. %s\n", *argv);
continue;
}
while(fgets(line, LINE_MAX, fr)){
if(!strstr(line, "iso")) continue;
if(AddString(line)) continue;
fprintf(fw, line);
}
fclose(fr);
}
fclose(fw);
return 0;
}
コンパイルが通らなかったらごめんなさい。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 14:03
by へろりくしょん
grep | sort の話も出てましたので、ついでにソートさせる版も書いておきます。
上のレスで編集してもいいのでせすけど、せっかくですので別に。
int compare(const void *str1, const void *str2)
{
return strcmp(*(char**)str1, *(char**)str2);
}
int main(int argc, char *argv[/url])
{
FILE *fr, *fw;
int i;
char line[LINE_MAX];
if(argc < 2){
printf("Usage : XTYPE filename1 [filename2 ...]\n");
return -1;
}
if(!(fw = fopen("notice.txt", "w"))){
printf("can not write file.\n");
return -3;
}
while(--argc){
++argv;
if(!(fr = fopen(*argv, "r"))){
printf("can not open file. %s\n", *argv);
continue;
}
while(fgets(line, LINE_MAX, fr)){
if(!strstr(line, "iso")) continue;
if(AddString(line)) continue;
}
fclose(fr);
}
qsort(table, useSize, sizeof(char*), compare);
for(i = 0;i<useSize;i++){
fprintf(fw, table);
}
fclose(fw);
return 0;
}
compare() 関数の追加と、main() 関数の置き換えです。
やっぱり動作確認はしてません。
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 14:09
by トマト
重複のないファイルがつくれました!
本当にありがとうございました!!
Re:複数あるファイル内の重複を探す方法
Posted: 2010年6月23日(水) 17:58
by Dixq (管理人)
解決マークはもうそのままで大丈夫ですか・・?