2011-10-05 8 views
1

私はこのようなテキストを持つファイルがあります:読むテキストファイルのステップバイステップの

#1#14#ADEADE#CAH0F#0#0..... 

を私は、#記号を次のテキストを見つけ、それを変数に格納し、書き込みをするコードを作成する必要があります#記号なしでファイルするが、前にスペースを入れる。だから、前のコードから、私が取得します:

1 14 ADEADE CAH0F 0 0...... 

を私が最初にPythonでそれをやってみましたが、ファイルは本当に大きなであり、それがファイルを処理するには、本当に巨大な時間がかかるので、私はC++でこの部分を書くことにしました。しかし、私はC++の正規表現について何も知らず、私は助けを求めています。私は簡単な正規表現ライブラリ(私はC++をよく知らない)またはよく書かれたものをお勧めしますか?小さな例(私はファイルへの転送を行う方法、fstreamを使う方法を知っていますが、前に述べたようにファイルの読み方について助けが必要です)を提供すればさらに良いでしょう。

+0

なぜ正規表現を使いたいのですか?文字列を解析する他の多くの方法がありますし、正規表現はこれほど単純なもののためにかなり激しいようです... – Zannjaminderson

+4

Ugh、このようなタスクの正規表現の過度な仕掛けではありませんか? – jrok

+0

['string :: replace']のファンではありません(http://www.cplusplus.com/reference/string/string/replace/)? –

答えて

4

これはstd::localeのための仕事のように見え、彼の信頼できる相棒imbue

#include <locale> 
#include <iostream> 


struct hash_is_space : std::ctype<char> { 
    hash_is_space() : std::ctype<char>(get_table()) {} 
    static mask const* get_table() 
    { 
    static mask rc[table_size]; 
    rc['#'] = std::ctype_base::space; 
    return &rc[0]; 
    } 
}; 

int main() { 
    using std::string; 
    using std::cin; 
    using std::locale; 

    cin.imbue(locale(cin.getloc(), new hash_is_space)); 

    string word; 
    while(cin >> word) { 
    std::cout << word << " "; 
    } 
    std::cout << "\n"; 
} 
+0

非常に良い考え;ちょうど私と一緒にクリックしましたが、あなたはすでにそれを投稿しました – sehe

+0

代わりにRegExライブラリを使用してみませんか?しかし、これは涼しいです。 –

+0

@Shuraneだから、入力ファイル全体を最初に一つの 'string'に読み込む必要はありません。 –

1

は、IMO、C++は、あなたの仕事のために最良の選択ではありません。しかし、C++でそれを行う必要があるなら、Boostライブラリの一部であるBoost.Regexを見てみることをお勧めします。

+0

* "今は2つの問題があります..." * – dmckee

+0

ありがとう、私はそれを見ます。私はそれを聞いたことがあります最高のライブラリのC + +の1つをブーストし、いくつかの有用な関数は、C + +の次のバージョンになります。 – ghostmansd

1

Unixをお使いの場合は、単純なsed 's/#/ /' <infile >outfileで十分です。

Sedは 'ストリームエディタ'の略です(そしてregexes!whoo!をサポートしています)ので、探しているパフォーマンスに適しています。

+0

Meh! 'tr"# "" "' – dmckee

+0

私はLinuxを使用していますが、自分のアプリケーションでsedを使用すると、Windowsのユーザーは同意しないと思います。 :-) – ghostmansd

+0

しかし 'sed'はもっと汎用性があります!不思議なことに、 'sed'は簡単にできないのは何ですか? –

0

申し訳ありませんが、私はちょうどコメントの代わりにこれを回答にしようとしています。正規表現は使用しないでください。これは、ほとんどの場合、このタスクのために残酷です。私はC++でちょっと錆びているので、醜いコードは投稿しませんが、基本的にはファイルを1文字ずつ解析し、#以外のものをバッファに入れてから書きます#を押すと、出力ファイルにスペースを加えて出力します。 C#では、この頭に浮かぶ解決するための少なくとも2つは本当に簡単な方法:

また
StreamReader fileReader = new StreamReader(new FileStream("myFile.txt"), 
           FileMode.Open); 
string fileContents = fileReader.ReadToEnd(); 
string outFileContents = fileContents.Replace("#", " "); 
StreamWriter outFileWriter = new StreamWriter(new FileStream("outFile.txt"), 
           Encoding.UTF8); 
outFileWriter.Write(outFileContents); 
outFileWriter.Flush(); 

を、私はあなたが何をすべきとは言わないよ

StringBuilder outFileContents = new StringBuilder(); 
string[] parts = fileContents.Split("#"); 
foreach (string part in parts) 
{ 
    outFileContents.Append(part); 
    outFileContents.Append(" "); 
} 

string outFileContents = fileContents.Replace("#", " "); 

を置き換えることができますこれらの方法のいずれか、またはC++のための私の提案されたメソッド、またはこれらのメソッドのいずれかが理想的ではありません - 私は文字列を解析する多くの方法があることをここで指摘しています。正規表現は非常に強力で、極端な状況ではsave the dayさえあるかもしれませんが、それはテキストを解析する唯一の方法ではなく、間違ったことに使用される場合でもdestroy the worldかもしれません。本当に。

regexの使用を強くお勧めする場合(または宿題のように強制されている場合)は、Chrisの話を聞きBoost.Regexを使用することをおすすめします。別の方法を試したい場合は、Boostにも良い文字列ライブラリがあることを理解しています。正規表現を使用する場合は、Cthulhuを調べてください。

+0

最初に、ghostmansdはファイル全体を文字列に読み込むことは望ましくありません。また、正規表現はかなりシンプルです。あなたはそれをテキストの変換として見ることができます。 HTMLのような言語の解析に使用しているのはひどいと考えられます。正規表現を使ってそれらを表現することはできません。そのような試みは失敗します。 –

+0

私は必ずしもファイル全体を文字列に読み替えるべきではありませんでした。他にもオプションがあります。正規表現を使って単純な限り、私はそこに引数がありません - このような単純なケースでは、他の選択肢があり、すべての問題を正規表現をハンマーとして釘として見ることに対して警告しようとしています。私はあなたの明確化に感謝します、@ Shurane。 – Zannjaminderson

0

入力に2つ(またはそれ以上)の連続した入力がある場合、それらは1つのスペースに変わるか、同じ数のスペースには#がありますか?

文字列全体を1つのスペースにする場合は、@ Robのソリューションがうまく動作するはずです。右、

#include <stdio.h> 

int main() { 
    int ch; 
    while (EOF!=(ch=getchar())) 
     if (ch == '#') 
      putchar(' '); 
     else 
      putchar(ch); 
    return 0; 
} 
0

だから、あなたはONE文字' 'と各ONE文字'#'置き換えたい:あなたがしたい場合

は各#は、それはおそらく最も簡単なだけで書き込むためのCスタイルのコードですが、空間になっていますか?

ファイルの構成を混乱させることなく、ファイルの任意の部分を正確に同じ長さの文字列に置き換えることができるので、簡単です。
このような置換を繰り返すことで、ファイルチャンクをチャンクで変換することができます。したがって、メモリ内のすべてのファイルを読み取ることは避けられます。これは、ファイルが非常に大きい場合に問題になります。

ここはPython 2.7のコードです。

チャンクによる置換チャンクは、それを速くするのが難しく、C++で同じものを書くのに苦労するでしょう。しかし、一般に、私がそのようなコードを提案したとき、それは実行の時間を満足に増加させました。

def treat_file(file_path, chunk_size): 
    from os import fsync 

    from os.path import getsize 
    file_size = getsize(file_path) 

    with open(file_path,'rb+') as g: 
     fd = g.fileno() # file descriptor, it's an integer 

     while True: 
      x = g.read(chunk_size) 
      g.seek(- len(x),1) 
      g.write(x.replace('#',' ')) 
      g.flush() 
      fsync(fd) 
      if g.tell() == file_size: 
       break 

コメント:

open(file_path,'rb+') 

それは、ファイルのポインタの正確な位置や動きを制御するためにバイナリモードでファイルを開くには、「B」絶対に義務です。
モードは'+'それはサイズCHUNK_SIZEのチャンクを読み込み、整数

x = g.read(chunk_size) 

だ、

fd = g.fileno() 

ファイルディスクリプタを読み込み、ファイルに書き込みができるようにすることです。読み込みバッファのサイズを与えるのは難しいですが、このバッファのサイズを見つける方法はわかりません。したがって、良いアイデアは、2つの価値の威力を与えることです。

g.seek(- len(x),1) 

ファイルのポインタは、チャンクの読み込みが行われた位置に戻されます。読んで最後のチャンクが少なく、長いchink_size

g.write(x.replace('#',' ')) 

よりも一般的である修正チャンク

g.flush() 
fsync(fd) 

これら2つの命令の力で同じ長さに書き込むためには、いないCHUNK_SIZElen(x)でなければなりません書き込まれていなければ、変更されたチャンクは書き込みバッファに残り、制御されない瞬間に書き込まれる可能性があります。

if g.tell() >= file_size: break 

その長さ(以下にCHUNK_SIZEする)であるどんなファイルの最後の部分の読み取り後、ファイルのポインタは、ファイルの最大位置にあることがFILE_SIZEを言うことで、プログラムが

を停止する必要があります

複数の連続した '### ...'を1つだけに置き換える場合は、短縮されたチャンクを書き込んでも未読の文字はまだ遠くまで消去されないため、この要件を満たすためにコードを簡単に変更できます。ファイル。 2つのファイルのポインタしか必要ありません。