std::ostream_iterator

[戻る]
よすむら 2006/05/08(月) 17:16:12
どなたかご教示をお願いします。
下記の文字列で始まるSJISテキストを下のコードで読みました。

★テキスト内容
あいおい■よしたろう
    相生■由太郎
    1867. 5.31


★画面出力
あいおい
よしたろう
相生
由太郎
1867.
5.31

std::locale::global(std::locale("ja"));
std::wifstream infile(path.string().c_str());
if ( !infile.is_open() )    return;
std::istream_iterator<std::wstring,wchar_t> first(infile);
std::istream_iterator<std::wstring,wchar_t> last;
std::copy(first, last, 
      std::ostream_iterator<std::wstring,wchar_t>(std::wcout, L"\n"));
infile.close();

SJISテキストをダンプすると、■は全角空白、「. ]の後部は半角空白、「相生」
「1867」の行頭はTABでした。
wifstreamでデータがUNICODEに変換されますが、その際上記の文字は文字列区切りとし
てL"\n"になってしまいました。
どうすれば、文字列区切りと見なさいようにできるでしょうか?
ちなみにデリミタ指定無しにすると、元テキストの改行すら削除されてしまいました。
よろしくお願い申し上げます。

REE 2006/05/08(月) 17:55:52
istream_iteratorを使うのを諦めて、istream::getline()を使うのが楽でしょう。

よすむら 2006/05/09(火) 11:04:34
REE様ご回答ありがとうございました。
boost::regex_splitも考えたんですが、難しくてあきらめました。
やはりistream::getline()が楽そうですね。
しかし気持としては、ostream_iteratorで改行のみをデリミタとする仕様あるいは拡張
があればと感じます。

REE 2006/05/09(火) 11:33:57
まあ、あってもいいとは思いますが、
いっそのことご自身で作られてみては?

dairygoods 2006/05/09(火) 12:30:02
istream_iterator は、operator>> で値を取り出すので、

class token {
 string value;
  ...
};
istream& operator>>(istream& in, token& t)
{
  好きな区切り文字まで読み出す;
}

というようなクラスを作ればよいのでは?

よすむら 2006/05/09(火) 13:51:06
先ほどostream_iteratorでなくistream_iteratorの仕様なのがわかりました。
dairygoods様のいわれることは、istream_iteratorの以下のメンバ関数中の

void _Getval()
{    // get a _Ty value if possible
    if (_Myistr != 0 && !(*_Myistr >> _Myval))
    _Myistr = 0;
}

>>をオーバーライドせよということでしょうか?

tetrapod 2006/05/09(火) 13:51:29
まったく読まずに istreambuf_iterator と言ってみるテスト

dairygoods 2006/05/09(火) 14:15:31
> >>をオーバーライドせよということでしょうか?

はい。
#この場合、オーバーライドでなくオーバーロードです。

struct line
{
  string value;
};
istream& operator>>(istream&in, line& l)
{
  return getline(in, l.value);
}
ostream& operator<<(ostream& out, const line& l)
{
  return out << l.value;
}

ifstream infile(ファイル名);
istream_iterator<line> first(infile);
istream_iterator<line> last;
copy(first, last, ostream_iterator<line>(cout, "\n"));

よすむら 2006/05/09(火) 15:35:00
コードありがとうございます。
しかし、

void _Getval()

から、

istream& operator>>(istream&in, line& l)

に入らず、

// basic_string INSERTERS AND EXTRACTORS
template<class _Elem,
    class _Traits,
    class _Alloc> inline
basic_istream<_Elem, _Traits>& __cdecl operator>>(
    basic_istream<_Elem, _Traits>& _Istr,
    basic_string<_Elem, _Traits, _Alloc>& _Str)

に入ってしまいます。
どうすればよいのでしょうか?

REE 2006/05/09(火) 16:02:35
istream_iterator<line> first(infile);
                ~~~~~~~
ここがちゃんとlineになっていますか?

よすむら 2006/05/09(火) 16:58:10
[[解決]]
REE様
dairygoods様
ありがとうございました、できました。
またiteratorの仕掛けがすこしだけ分かりました(¨;)。
ひとり言です(ctype::spaceが気になります...)

よすむら 2006/05/12(金) 18:38:17
>>しかし気持としては、ostream_iteratorで改行のみをデリミタとする仕様あるいは拡
張があればと感じます。

気にしたctype::space...ファセットを使用した解決法がネット検索で見つかりまし
たのでご報告しておきます。
(コメントアウト以外が原文<archive373-2006-2-805727.html>)。
長文ですみませんです。

// start of file
#include <vector>
#include <algorithm>
#include <iterator>
#include <locale>
#include <istream>
#include <fstream>

template <class charT>
struct custom_ctype : public std::ctype<charT>
{
  typedef std::ctype<charT> base;

  custom_ctype(std::basic_string<charT> spaceChars)
    :m_spaceChars(spaceChars){}

protected:
  virtual bool do_is(base::mask m, charT c) const
  {
    base::mask M;
    do_is(&c, &c + 1, &M);
    return (M & m) == m; //check M has at least all bits of m set.
  }

  virtual const charT* do_is(const charT* low, const charT* high, base::mask* 
vec) const
  {
    base::do_is(low, high, vec);
    for (; low != high; ++low, ++vec) {
      if (m_spaceChars.find(*low) != std::basic_string<charT>::npos)
        *vec |= ctype_base::space;
      else
        *vec &= ~ctype_base::space;
    }
    return high;
  }

private:
  std::basic_string<charT> m_spaceChars;
  custom_ctype(const custom_ctype& rhs);
  custom_ctype& operator=(const custom_ctype& rhs);
};

template<>
struct custom_ctype<char> : public std::ctype<char>
{
  custom_ctype(std::string const& spaceChars):
  std::ctype<char>(get_table(spaceChars), true) {}

  static std::ctype_base::mask const* get_table(std::string const& spaceChars)
  {
    std::ctype_base::mask* table = new
    std::ctype_base::mask[std::ctype<char>::table_size];
    std::transform(classic_table(),
    classic_table() + std::ctype<char>::table_size, table, nospacer());
    for (int i = 0; i != spaceChars.size(); ++i) {
      table[spaceChars[i]] |= std::ctype_base::space;
    }
    return table;
  }

private:
  struct nospacer
  {
    std::ctype_base::mask operator()(std::ctype_base::mask m) const {
      return m & ~ctype_base::space;
    }
  };

  custom_ctype(const custom_ctype& rhs);
  custom_ctype& operator=(const custom_ctype& rhs);
};

#include <iostream>
#include <sstream>

int main()
{
//  {
//  std::wistringstream iss(L"hello world,");
  std::wifstream infile(パス名);
  std::locale loc(std::locale(), new custom_ctype<wchar_t>(L""));
//  iss.imbue(loc);
//  std::wstring s, t;
//  iss >> s >> t;
//  std::wcout << s << L'\n' << t << std::endl;
//  }
  infile.imbue(loc);
  if ( !infile.is_open() )    return 0;
  std::istream_iterator<std::wstring,wchar_t> first(infile);
  std::istream_iterator<std::wstring,wchar_t> last;
  std::copy(first, last, 
      std::ostream_iterator<std::wstring,wchar_t>(std::wcout, L"\n"));
  infile.close();
}
// end of file

古いスレッドには追加発言できません。