こんにちは。
早速本題に入ります。
あるテキストには次のようになっています。
abc
def
ghi
このようになっている場合、
上から2番目(この場合だとdef)を取得したいのですが、
これはどうすれば良いのでしょうか?
どなたかご教授お願いします。
ごめんなさい。題名が明らかに違ってました(^^;
本当は「改行された文字を読み取るには?」でしたね。
タイトルは,「指定された行を読み取るには?」あたりが妥当かと。
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));
に変更する必要アリ。
改行コードで判別すればよいかと思います。
「改行コードの1バイト後ろ〜次の改行コードの1バイト前まで」ってな具合でどうでしょう。
テキストってのは,文字列のこと?
だったら,ifstreamでなくistringstreamにすれば同じことができます。
重さん、YuOさん、どうもありがとうございました。
あの…追加で申し訳ないのですが、
テキストファイルの「改行コード」とはどんなものでしょうか?
テキストファイルに「\n」を出力しても改行してくれませんでした。
あつかましいお願いですが、これも教えてください。
どうか、お願いします。
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.
ですかね。
あの…本当に申し訳ないのですが、
YuOさんの場合、C++言語であってCでは動かないのでは?
もし宜しければ、Cの方法の方が助かります
(本当に我が侭ばかりですみません。でもこれだけは知りたいんです・・!)
とりあえず,指定がなかったので処理が簡単なC++言語の方を使ったのですが。
考え方自体は,C言語でも同じです。
ただし,ライブラリのサポートを受けられるC++言語と違い,
C言語ではメモリをきっちり扱わないといけません。
基本的にはgetlineのかわりにfgetsを使うことになります。
よく考えたら,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と同じように使えるはず。
本当にありがとうございました!!!
確かにクラスを使ったC++言語の方がカンタンなのかもしれません。
今度C++にも挑戦してみることにします。
ひとまず、これでなんとかできそうです!
我が侭を聞いてくださり、本当にありがとうございました!
ツイート | ![]() |