ファイルの中で改行するには?

解決


ryotaro331  URL  2002-06-01 14:45:24  No: 50202  IP: [192.*.*.*]

こんにちは。
早速本題に入ります。

あるテキストには次のようになっています。

abc
def
ghi

このようになっている場合、
上から2番目(この場合だとdef)を取得したいのですが、
これはどうすれば良いのでしょうか?
どなたかご教授お願いします。

編集 削除
ryotaro331  URL  2002-06-01 14:47:09  No: 50203  IP: [192.*.*.*]

ごめんなさい。題名が明らかに違ってました(^^;
本当は「改行された文字を読み取るには?」でしたね。

編集 削除
YuO  2002-06-01 15:04:46  No: 50204  IP: [192.*.*.*]

タイトルは,「指定された行を読み取るには?」あたりが妥当かと。


a) 順番に読んでいく方法

一行ずつ読み捨てていけば,特定の行を見つけるのは簡単ですよね。

std::ifstream fin(filename);
std::string str;
for (int i = 0; i < line; ++i) {
    if (fin.eof()) {
        str.erase();
        break;
    } else std::getline(fin, str);
}
// strがファイルfilenameのline行目

b) 全部読んでしまう方法

行に分割して配列に代入すれば,あとはO(1)でアクセス可能。

std::ifstream fin(filename);
std::istream_iterator<std::string> begin(fin), end;
std::vector<std::string> v(begin, end);
// v[line - 1]がline行目

※bの3行目は古いVC++(VC++ 6.0およびそれ以前)ではコンパイルできないので,
std::vector<std::string> v;
std::copy(begin, end, std::back_inserter(v));
に変更する必要アリ。

編集 削除
 2002-06-01 15:09:26  No: 50205  IP: [192.*.*.*]

改行コードで判別すればよいかと思います。
「改行コードの1バイト後ろ〜次の改行コードの1バイト前まで」ってな具合でどうでしょう。

編集 削除
YuO  2002-06-01 16:35:08  No: 50206  IP: [192.*.*.*]

テキストってのは,文字列のこと?
だったら,ifstreamでなくistringstreamにすれば同じことができます。

編集 削除
ryotaro331  URL  2002-06-02 14:05:59  No: 50207  IP: [192.*.*.*]

重さん、YuOさん、どうもありがとうございました。
あの…追加で申し訳ないのですが、
テキストファイルの「改行コード」とはどんなものでしょうか?
テキストファイルに「\n」を出力しても改行してくれませんでした。
あつかましいお願いですが、これも教えてください。
どうか、お願いします。

編集 削除
YuO  2002-06-02 18:09:54  No: 50208  IP: [192.*.*.*]

MS-DOS/Windowsでの改行コードは,CrLfです。
fopenやfstreamを使って,テキストファイルとして開いた場合,
ライブラリが\nとCrLfを変換してくれます。
#Windows APIの場合はCrLfを使う。

でもって,バイナリファイルの場合,通常CrLfは\r\nで扱います。


ちなみに,Unixでの改行コードはLf(Nl), MacintoshではCrです。
どちらも,C/C++のライブラリでは\nで扱います。


そんでもって,Cの仕様では,
\n (New-Line) Moves the active position to the initial position of the next line.
\r (Carriage-Return) Moves the active position to the initial position of the current line.
となっています。
これに似せて書くなら,Lf (Line-Feed)は,
Lf (Line-Feed) Moves the active position to the current position of the next line.
ですかね。

編集 削除
ryotaro331  URL  2002-06-02 19:12:11  No: 50209  IP: [192.*.*.*]

あの…本当に申し訳ないのですが、
YuOさんの場合、C++言語であってCでは動かないのでは?
もし宜しければ、Cの方法の方が助かります
(本当に我が侭ばかりですみません。でもこれだけは知りたいんです・・!)

編集 削除
YuO  2002-06-02 19:44:36  No: 50210  IP: [192.*.*.*]

とりあえず,指定がなかったので処理が簡単なC++言語の方を使ったのですが。

考え方自体は,C言語でも同じです。
ただし,ライブラリのサポートを受けられるC++言語と違い,
C言語ではメモリをきっちり扱わないといけません。
基本的にはgetlineのかわりにfgetsを使うことになります。

編集 削除
YuO  2002-06-03 03:54:25  No: 50211  IP: [192.*.*.*]

よく考えたら,bの方法は使えないね……。
istreamline_iteratorでも作るか。

#include    <iterator>
#include    <string>
#include    <istream>
#include    <memory>

#if defined(_MSC_VER) && _MSC_VER < 1300 && !defined(STD_PTRDIFF_T_DEFINED)
#define STD_PTRDIFF_T_DEFINED
namespace std {
    using ::ptrdiff_t;
}
#endif

template <typename T, class Ch = std::char_traits<T>, class A = std::allocator<T>, typename D = std::ptrdiff_t>
class istreamline_iterator : public std::iterator<std::input_iterator_tag, T, D
#if !defined(_MSC_VER) || _MSC_VER >= 1300
        , const std::basic_string<T, Ch, A> *, const std::basic_string<T, Ch, A> &
#endif
> {
    typedef istreamline_iterator<T, Ch, A, D>   this_type;

public:
    typedef T   char_type;
    typedef Ch  traits_type;
    typedef std::basic_istream<T, Ch>   istream_type;
    typedef std::basic_string<T, Ch, A> string_type;

    istreamline_iterator (void) : in_stream(0) {}
    istreamline_iterator (istream_type & s) : in_stream(&s) {}

    const string_type & operator* (void) const {
        return value;
    }
    const string_type * operator-> (void) const {
        return &(operator*());
    }

    this_type & operator++ (void) {
        std::getline(*in_stream, value);
        if (in_stream->eof()) in_stream = 0;
        return *this;
    }
    this_type operator++ (int) {
        this_type tmp = *this;
        ++*this;
        return tmp;
    }

    bool operator== (const this_type & rhs) const {
        return in_stream == rhs.in_stream;
    }
    bool operator!= (const this_type & rhs) const {
        return !(*this == rhs);
    }
private:
    istream_type * in_stream;
    string_type value;
};

こんな感じかな?
たぶん,istream_itertorと同じように使えるはず。

編集 削除
ryotaro331  URL  2002-06-03 19:47:33  No: 50212  IP: [192.*.*.*]

本当にありがとうございました!!!
確かにクラスを使ったC++言語の方がカンタンなのかもしれません。
今度C++にも挑戦してみることにします。
ひとまず、これでなんとかできそうです!
我が侭を聞いてくださり、本当にありがとうございました!

編集 削除