View on GitHub

boost_spirit_guide

文字パーサ

基本

char型

ルールは char_ になりますが、想定する文字コードに応じて名前空間が異なります。(namespace qi = boost::spirit::qi)

この辺の設計は流動的ですので、standard, standard_wide の2つを押さえておけば問題ありません。
ascii 及び iso8859_1 は、standard に含まれます。
shift_jis, euc_jp という名前空間は存在しませんが、standard に含まれます。
utf-8 は standard に含まれます。ただし、utf-8 を iostream の codecvt を経由して wchar_t で処理する場合は standard_wide に含まれます。

文字型(属性) ルール 説明
char qi::standard::char_ 1文字にマッチします。
wchar_t qi::standard_wide::char_ 1文字ワイド・キャラにマッチします。

1文字読み込む(char版)

c++:char 例
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::string input = "a";
  char n;
  qi::parse( input.begin(), input.end(), qi::standard::char_, n );
  std::cout << n << std::endl;
  return 0;
}

1文字読み込む(wchar_t版)

c++:wchar 例
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::wstring input = L"日";
  wchar_t n;
  qi::parse( input.begin(), input.end(), qi::standard_wide::char_, n );
  std::wcout.imbue(std::locale(""));
  std::wcout << n << std::endl;
  return 0;
}

charリテラル

文字型(属性) ルール サンプル 説明
qi::unused_type qi::lit(1文字キャラ値) qi::lit(‘X’) 1文字値にマッチします。
qi::unused_type qi::lit(1文字ワイドキャラ値) qi::lit(L’X’) 1文字ワイドキャラ・リテラルにマッチします。

qi::unused_type とは、属性においては値として取り出されない型を示します。

文字列リテラル

文字型(属性) ルール サンプル 説明
qi::unused_type qi::lit(文字列) qi::lit(“固定文字列”) 指定された文字列にマッチします。
qi::unused_type qi::lit(ワイドキャラ文字列) qi::lit(L”固定文字列”) 指定されたワイドキャラ文字列にマッチします。

文字列定数と同じかチェックする(char版)

c++:文字列定数 例
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::string input = "こんにちは"; // Windows では SJIS解釈、他では UTF-8解釈
  auto s = input.begin();
  auto e = input.end();
  qi::parse( s, e, qi::lit("こんにちは") );
  //qi::parse( s, e, qi::lit("こんにちわ") );
  std::cout << ((s == e) ? "マッチ" : "エラー") << std::endl;
  return 0;
}

qi::parse に渡されるイテレータは入力値の解析範囲を示します。
引数の開始位置は参照渡しで、解析後にマッチが完了できた位置になっています。
s == e ならば、フルマッチを示し、s != e ならば、マッチしなかった事を示します。
コメントアウトされた行で解析をすると、結果がマッチからエラーに変わります。  

文字列

文字型(属性) ルール サンプル
std::string +(qi::standard::char_)  
std::wstring +(qi::standard_wide::char_)  

ここでルールに + という記号が登場しました。 ルールに適応できる演算子で、1回以上の繰り返しを示します。
似た演算子で * という0回以上の繰り返しを示すものもあります。
正規表現では同じ意味を持つ + * は後置演算子ですが、C++ の文法で実現するために前置演算子として実装されています。
char型の繰り返しをstring型として取り出せるところが巧妙です。

文字列を取り出す(wchar_t版)

c++:文字列定数2 例
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::wstring input = L"こんにちは";
  std::wstring n;
  qi::parse( input.begin(), input.end(), +qi::standard_wide::char_, n );
  std::wcout.imbue(std::locale(""));
  std::wcout << n << std::endl;
  return 0;
}

文字条件指定

qi::standard::char_, qi::standard_wide::char_ に対してマッチする文字を指定する事が可能です。
2通りの指定方法があります

開始から終了までの範囲指定

引数 説明
qi::standard::char_( char arg1, char arg2 ) arg1: 開始文字, arg2: 終了文字, 開始文字から終了文字までの文字にマッチする qi::standard::char_(‘A’,’Z’);
qi::standard_wide::char_( wchar_t arg1, wchar_t arg2 ) arg1: 開始文字, arg2: 終了文字, 開始文字から終了文字までの文字にマッチする qi::standard_wide::char_(L’A’, L’Z’);

文字範囲指定された文字列を取り出す

c++:範囲指定 例
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::string input = "FBIJHCBFIJXXX";
  std::string n;
  qi::parse( input.begin(), input.end(), +qi::standard::char_('A', 'J'), n );
  std::cout << n << std::endl; // Xはルールにマッチしないので FBIJHCBFIJ まで表示されます
  return 0;
}

文字の範囲指定で、SJIS、UTF-8(ASCII以外の文字)は指定できません。
それでは qi::standard_wide の wchar_t でなら指定できるでしょうか?
「答えは半分は解決できるが、根本的には解決しない」です。
異体字などUNICODEの定義は複雑で単純に範囲でくくれるような代物ではありません。

ASCII以外の文字の取扱いは、後で説明します。

書式による文字指定

引数 説明
qi::standard::char_( const char* arg ) arg: 文字指定 qi::standard::char_(“A-Z”);
qi::standard_wide::char_( const wchar_t* arg ) arg: 文字指定 qi::standard_wide::char_(L”a-fA-F0-9”);

文字指定には、指定したい文字を列挙します。ただし - 文字は先頭で指定する必要があり、2番目以降に出現した場合は - の前後の文字範囲を指定した事になります。
“A-Z” の場合、AからZの範囲の文字を指定した事になります。

文字指定された文字列を取り出す

c++:文字指定(個別に文字を指定) 例
#include <boost/spirit/include/qi.hpp>
#include <iostream>
#include <string>

namespace qi = boost::spirit::qi;

int main() {
  std::wstring input = L"FBIJHABFIJXXX";
  std::wstring n;
  qi::parse( input.begin(), input.end(), +qi::standard_wide::char_(L"ABFHIJ"), n );
  std::wcout.imbue(std::locale(""));
  std::wcout << n << std::endl;
  return 0;
}

文字分類パーサ

アルファベット、数字、空白文字、改行文字、というように、分類された文字のルールです。
文字パーサ同様、想定する文字コードに応じて名前空間が異なります。(namespace qi = boost::spirit::qi)

名前空間 ns は、以下の何れかに該当します

文字分類 ルール  
アルファベット ns::alpha a-zA-Z  
アルファベット、または、数字 ns::alnum a-zA-Z0-9  
数字 ns::digit 0-9  
表示可能文字 ns::graph スペース!”#$%&’()=~^¥\|{}[]@`*+-/?><,.a-zA-Z0-9  
アルファベット小文字 ns::lower a-z  
アルファベット大文字 ns::upper A-Z  
句読 ns::punct !”#$%&’()*+,-./:;<=>?@[\]^_`{|}~  
ブランク ns::blank スペース、タブ  
スペース ns::space スペース、タブ、CR、LF  
16進文字 ns::xdigit 0-9a-fA-F  

名前空間の指定により文字判定の実装が異なります。判定のコードは、std::isalpha といった locale のコードに依存します。
localeの実装は、各プラットフォームが提供するライブラリに依存します。
Visual C++ の DEBUGバージョンでは ASSERT マクロにより isalpha 系の関数呼び出しが qi::standardでutf-8のコードを通すと範囲チェックエラーになります。
このように実装がデリケートなので、必要な分類は ns::blank, ns::space を除いて自分で記述した方が良いかもしれません。

漢字を指定したい場合には、これら文字分類パーサでは足りず、専用のルールを記述する必要があります。