<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>はらぺこ日誌 &#187; 正規表現</title>
	<atom:link href="https://blog.harapeko.jp/tag/%e6%ad%a3%e8%a6%8f%e8%a1%a8%e7%8f%be/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.harapeko.jp</link>
	<description>株式会社はらぺこ 公式ブログ</description>
	<lastBuildDate>Mon, 30 Oct 2017 14:32:56 +0000</lastBuildDate>
	<language>ja</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.9.2</generator>
	<item>
		<title>C++11 で Unicode プログラミングのススメ</title>
		<link>https://blog.harapeko.jp/2011/12/27/cpp11-unicode/</link>
		<comments>https://blog.harapeko.jp/2011/12/27/cpp11-unicode/#comments</comments>
		<pubDate>Mon, 26 Dec 2011 16:33:41 +0000</pubDate>
		<dc:creator><![CDATA[村山 俊之]]></dc:creator>
				<category><![CDATA[技術メモ]]></category>
		<category><![CDATA[Boost]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[C++0x]]></category>
		<category><![CDATA[C++11]]></category>
		<category><![CDATA[Unicode]]></category>
		<category><![CDATA[wchar_t]]></category>
		<category><![CDATA[文字セット]]></category>
		<category><![CDATA[文字列処理]]></category>
		<category><![CDATA[正規表現]]></category>

		<guid isPermaLink="false">http://blog.harapeko.jp/?p=229</guid>
		<description><![CDATA[このエントリは、C++11 Advent Calendar 2011 への参加記事です。 初心者表明を免罪符に [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>このエントリは、<a href="http://atnd.org/events/21936">C++11 Advent Calendar 2011</a> への参加記事です。</p>
<p>初心者表明を免罪符にするつもりは毛頭無いのですが、 C++0x/11 の学習、およびそれを用いた経験はまだまだ浅いため、内容的に拙い部分が多々あることを、あらかじめご容赦願いたいと思います <tt>m(_ _)m</tt> 。ていうか突っ込みだいかんげいでつ。</p>
<p>一応 <a href="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf">ISO/IEC 14882:2011 の draft &#8220;n3242&#8243;</a> を参照しています。 GCC は 4.7 入れるの面倒だったので、動作確認できるものについては Ubuntu 11.10 に入っていた 4.6.1 を用いています。</p>
<h3>Unicode に対応したリテラル</h3>
<p>文字リテラルについてはドラフトの 2.14.3、文字列リテラルについては 2.14.5 に記述があります。<br />
<span id="more-229"></span><br />
文字リテラルには従来の</p>
<pre>
'a'
L'あ'
</pre>
<p>といったスタイルに加えて、</p>
<pre>
u'\u00a9'   // コピーライト記号
U'\U0002000b'  // 丈の右上に点がついた字
</pre>
<p>といったスタイルが追加されました。想定されるべき対応関係を表にすると以下の通りになります。</p>
<table>
<tr>
<th>記述スタイル</th>
<th>文字セット</th>
<th>物理型</th>
</tr>
<tr>
<td><code>'</code>&#8230;<code>'</code></td>
<td>所謂 C 文字。<br />マルチバイトの 1 オクテットでもいいし、まぁ、何でもあり。</td>
<td><code>char</code></td>
</tr>
<tr>
<td><code>l'</code>&#8230;<code>'</code> または <code>L'</code>&#8230;<code>'</code></td>
<td>ユニバーサル文字セット (UCS)。</td>
<td><code>wchar_t</code></td>
</tr>
<tr>
<td><code>u'</code>&#8230;<code>'</code></td>
<td>UTF-16</td>
<td><code>char16_t</code></td>
</tr>
<tr>
<td><code>U'</code>&#8230;<code>'</code></td>
<td>UTF-32</td>
<td><code>char32_t</code></td>
</tr>
</table>
<p>文字列リテラルではさらに <code>u8</code> という接頭子も使えます。</p>
<pre>
u8"Copyright \u00a9 2011 Harapeko, Inc."    // \u00a9 は UTF-8 のオクテット列 [C2 A9] に変換される
u"\U0002000bは「丈」の字にクリソツ"         // \U0002000b は UTF-16 の該当するサロゲートペアに変換される…ハズ
</pre>
<p>対応関係の表は、…面倒くさいからもういいか。</p>
<p>あとさらっと流しちゃいましたが、 Unicode 用のエスケープ文字も追加されました。<q><code>\uNNNN</code></q> は 16bits の、 <q><code>\UNNNNNNNN</code></q> は 32bits の UCS を表現できます。上記の例のように、適切な文字列リテラル内で使用すれば、対応する文字セットの数値列に適宜変換されるはずです。この辺の説明はドラフトの 2.3 にありますが、以下の説明の通り、あくまで UCS の文字値を表現するものであって UTF の数値列を表現するものではないので、 <code>\uNNNN</code> の形式でサロゲートペアの上位代用符号位置に相当する値を指定することはできません。</p>
<blockquote cite="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf" title="Working Draft, Standard for Programming<br />
Language C++ (N3242=11-0012)"><p>
The character designated by the universal-character-name \UNNNNNNNN is that character whose character<br />
short name in ISO/IEC 10646 is NNNNNNNN; the character designated by the universal-character-name \uNNNN<br />
is that character whose character short name in ISO/IEC 10646 is 0000NNNN. If the hexadecimal value for a<br />
universal-character-name corresponds to a surrogate code point (in the range 0xD800.0xDFFF, inclusive),<br />
the program is ill-formed. Additionally, if the hexadecimal value for a universal-character-name outside the<br />
c-char-sequence, s-char-sequence, or r-char-sequence of a character or string literal corresponds to a control<br />
character (in either of the ranges 0&#215;00.0x1F or 0x7F.0x9F, both inclusive) or to a character in the basic<br />
source character set, the program is ill-formed.15
</p></blockquote>
<h3>Unicode に対応した物理型</h3>
<p>Unicode に対応した型については、ドラフトの 3.9.1 に説明があります。重要なのは多分以下の箇所。</p>
<blockquote cite="http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf" title="Working Draft, Standard for Programming<br />
Language C++ (N3242=11-0012)">
<ol start="5">
<li>Type wchar_t is a distinct type whose values can represent distinct codes for all members of the largest<br />
extended character set specified among the supported locales (22.3.1). Type wchar_t shall have the same<br />
size, signedness, and alignment requirements (3.11) as one of the other integral types, called its underlying<br />
type. Types char16_t and char32_t denote distinct types with the same size, signedness, and alignment as<br />
uint_least16_t and uint_least32_t, respectively, in &lt;stdint.h&gt;, called the underlying types.</li>
</ol>
</blockquote>
<p>エーゴは苦手なんですが、ここを読む限り、<code>wchar_t</code> はサポートするロケールに含まれるもっとも大きな値の文字値を表現できるのに十分なサイズの整数型であることが補償されてなきゃいけなさそうに見えます。 <code>wchar_t</code> については<a href="http://blog.harapeko.jp/2009/07/25/wchar_t-suck/" title="はらぺこ日誌? ブログアーカイブ ? 頼りなさげな wchar_t">大分昔に見捨てている</a>んですが <tt>(^_^;</tt> 、VC++2010 だと 32bits 整数に変更されていたりするんでしょうか…?</p>
<p># <a href="http://msdn.microsoft.com/ja-jp/library/s3f49ktz.aspx" title="Data Type Ranges (MSDN)">この辺</a>とか見る限り、やっぱり <code>unsigned short int</code> 相当、のままみたいですね… orz</p>
<p><code>char16_t</code> と <code>char32_t</code> は、それぞれ UTF-16、 UTF-32 を扱うための型と考えて差し支えなさそうです。</p>
<h3>「内部文字」のポリシー</h3>
<p>型についての想定を考えるならば、プログラムが内部で扱う文字データは、 C++11 では <code>wchar_t</code> を使用するべきであるように思われます。将来的にはそうなってゆくべきなのでしょう。しかし過去との互換性などの観点から、各ベンダーの <code>wchar_t</code> に対する取り扱いは当面現状維持か、もしくは段階的な仕様変更 (コンパイラオプションでの切り替え等) となっていくことが予想されます。</p>
<p>それに対し、 UTF-32 に関して言えば、恐らく向こう十何年かぐらいは「1要素 = UCS 1文字」であり続けるのではないかと思われます。従って、内部文字への要件として「1文字を 1つの数値のみで扱いたい」というのがあるのであれば、当面は <code>char32_t</code> と <code>U"</code>&#8230;<code>"</code> 形式のリテラルを用いるのが良さそうです。</p>
<table>
<tr>
<th>要件</th>
<th>選択すべき型と文字セット</th>
</tr>
<tr>
<td>
<ul>
<li>1文字を 1つの数値のみで扱いたい</li>
<li>メモリー使用量は気にしないか、32bits 幅でも十分管理可能</li>
</ul>
</td>
<td><code>char32_t</code>、 UTF-32</td>
</tr>
<tr>
<td>
<ul>
<li><code>&lt;</code>(<code>boost/</code>)<code>regex&gt;</code> を使いたい (後述)</li>
<li>UTF-8 のクセに精通しているのでマルチバイトでも気にならない</li>
<li>メモリー使用量を極力抑えたい</li>
</ul>
</td>
<td><code>char</code>、 UTF-8</td>
</tr>
<tr>
<td>
<ul>
<li>とにかく <code>wchar_t</code> を使い慣れている</li>
<li>数十年後の未来との互換性、汎用性に賭けたい</li>
</ul>
</td>
<td><code>wchar_t</code>、 UCS</td>
</tr>
</table>
<h3>char32_t で文字列置換を試してみる</h3>
<p>そんなわけで、実際に UTF-32 を内部文字の文字セットとして採用したプログラム例を作ってみることにしました。内容的には、静的に用意した文字列内のすべての「くま」を「ぱんだ」に置き換える、という簡単なものです。</p>
<pre>
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;string&gt;

using namespace std;

int main()
{
    u32string before = U&quot;てくまくまやこんてくまくまやこん むらやましゃちょうよ おおきなくまにな～ぁれ&quot;;
    u32string after;
    u32string kuma = U&quot;くま&quot;;
    u32string panda = U&quot;ぱんだ&quot;;

    auto start_it = before.begin();
    auto find_it = start_it + (kuma.size() - 1);
    while (find_it &lt; before.end()) {
        int cnt = 0;
        auto stop_it = find_if(kuma.rbegin(), kuma.rend(), [&amp;cnt, find_it](char32_t letter) {
            return *(find_it - cnt++) != letter;
        });
        if (stop_it != kuma.rend()) {
            find_it += cnt;
            continue;
        }
        // くまを発見、ぱんだに変身!!
        after.append(start_it, find_it - (kuma.size() - 1));
        after += panda;
        start_it = find_it + 1;
        find_it = start_it + (kuma.size() - 1);
    }
    after.append(start_it, find_it);

    cout &lt;&lt; &quot;before: &quot; &lt;&lt; before.size() &lt;&lt; endl;
    cout &lt;&lt; &quot;after: &quot; &lt;&lt; after.size() &lt;&lt; endl;

    return 0;
}
</pre>
<p>えっと… アルゴリズムの説明とかはいいですよね? 文字列の先頭からと検索語の後からで評価して、完全一致しなかった場合は一致した数値の数だけ読み飛ばして、を繰り返すというオーソドックスなやり方です。これだったらかっこつけて <code>find_if</code> とか使わんで <code>for</code> で回しても大して変わらんやんとかそういう突っ込みはさておき <tt>(^_^;</tt> 。</p>
<p>GCC4.6/Ubuntu での実行結果は以下の通り。</p>
<pre>
murachi@ubuntu-vbox:~/otoco/trunk/sample$ g++ -std=c++0x -o kumapan-n kumapan-n.cpp 
murachi@ubuntu-vbox:~/otoco/trunk/sample$ ./kumapan-n
before: 39
after: 44
murachi@ubuntu-vbox:~/otoco/trunk/sample$ 
</pre>
<p>実行結果として置換前後の <code>u32string::size()</code> を表示しています。 5つある「くま」が「ぱんだ」に置き換えられたので、その数が 5 増えています。増える筈の文字数と一致するので、正しく動作しているように見えます。</p>
<h3>iconv を使って実際に出力してみる</h3>
<p>さて、実際の文字列を出力してみたいのですが、このままだとロケールが UTF-8 で動作している端末上では表示できません。ファイルに出力してテキストエディタで、という手もありますが、せっかくなので libiconv を使って指定した文字セットに変換して出力、ということをやってみることにしましょう。</p>
<p>libiconv の利用に際しては、お手製のラッパークラスを作成することで対応しました。作成したソースコードを以下にリンクします。</p>
<ul>
<li><a href="http://developer.harapeko.jp/trac/original/otoco/browser/trunk/sample/EncodeString.hpp?rev=16">EncodeString.hpp</a></li>
<li><a href="http://developer.harapeko.jp/trac/original/otoco/browser/trunk/sample/EncodeString.cpp?rev=16">EncodeString.cpp</a></li>
</ul>
<p>このクラスは<a href="http://blog.harapeko.jp/2010/09/22/utf-8-is-nice/" title="はらぺこ日誌? ブログアーカイブ ? UTF-8 もイマイチだが…">過去の記事</a>においても使用しておりますが、 C++11 の勉強も兼ねて (?)、内部文字に使用する物理型と文字セットをテンプレートパラメータに指定できるテンプレートクラスに書き換えています (あ、過去の記事でのソースへのリンク先が最新版になっちゃってる…直さなきゃ…)。</p>
<p>そして先ほどのサンプルプログラムは、最初の方で <code>EncodeString.hpp</code> を <code>#include</code> し、</p>
<pre>
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;string&gt;

#include &quot;EncodeString.hpp&quot; // ←

using namespace std;
</pre>
<p>最後の方で出力内容を以下のように修正します。</p>
<pre>
    cout &lt;&lt; &quot;before: &quot; &lt;&lt; EncodeString&lt;char32_t, chset_Utf32&gt;(before, chset_Utf8).getCharArray() &lt;&lt; endl;
    cout &lt;&lt; &quot;after: &quot; &lt;&lt; EncodeString&lt;char32_t, chset_Utf32&gt;(after, chset_Utf8).getCharArray() &lt;&lt; endl;
</pre>
<p>Windows 環境とかで Shift JIS (CP-932) で出力したい人は、 <code>chset_Utf8</code> を <code>chset_Cp932</code> に置き換えてあげれば ok です。GCC4.6/Ubuntu での実行結果は以下の通り。</p>
<pre>
murachi@ubuntu-vbox:~/otoco/trunk/sample$ g++ -std=c++0x -o kumapan EncodeString.cpp kumapan.cpp 
murachi@ubuntu-vbox:~/otoco/trunk/sample$ ./kumapan
before: てくまくまやこんてくまくまやこん むらやましゃちょうよ おおきなくまにな～ぁれ
after: てぱんだぱんだやこんてぱんだぱんだやこん むらやましゃちょうよ おおきなぱんだにな～ぁれ
murachi@ubuntu-vbox:~/otoco/trunk/sample$ 
</pre>
<p>環境によっては libiconv を別途導入してコンパイルオプションに <code>-liconv</code> を付け加える必要があるかもしれません (MinGW とか←動作未確認)。</p>
<h3>正規表現を使いたい</h3>
<p>さて、上記のサンプルでさらっと <code>u32string</code> とか使っちゃってますが、このシノニムはドラフトの 21.3 にてちゃんと明記された標準のものです。もちろん、 <code>u16string</code> というのも存在します (<code>u8string</code> は無いので、考慮されているのはアラインメントのみと考えるべきですが…)。</p>
<p>しかし、「28 Regular expressions library」の章においては、 <code>char32_t</code> という文字はカケラも hit しません。標準の <code>&lt;regex&gt;</code> においては、 <code>char16_t</code>、 <code>char32_t</code> への対応は見送られてしまっているようです。</p>
<p>もちろん、<code>basic_regex</code> はテンプレートクラスなのですから、自分でテンプレートパラメータを指定してあげればうまくいきそうに見えます。しかし、<a href="http://blog.harapeko.jp/2010/09/22/u32regex-bad-cast/" title="はらぺこ日誌? ブログアーカイブ ? char32_t だと regex が使えない">同様の試みを Boost.Regex について行った際には、 <code>std::bad_cast</code> 例外が送出されてプログラムがエラー終了してしまいました</a>。将来的には、あるいは処理系によってはうまく動かせる (ようになる) のかもしれませんが、あまり期待は持たない方が良いかもしれません…。</p>
<p># そもそも <a href="http://gcc.gnu.org/onlinedocs/libstdc++/manual/status.html#status.iso.200x" title="C++ 200x - Chapter 1. Status (libstdc++)">GCC (libstdc++) では <code>&lt;regex&gt;</code> 自体がまだちゃんと実装されてなかったり</a>… orz</p>
<p>もっとも、<a href="http://blog.harapeko.jp/2011/09/21/boostregex-icu-with-char32_t/" title="はらぺこ日誌? ブログアーカイブ ? Boost.Regex の ICU 拡張と char32_t は相性がいいかも?">Boost.Regex の ICU 拡張における <code>UChar32</code> と <code>char32_t</code> (およびそれらの配列へのポインタ) を無理矢理キャストして使うと割と上手く行くっぽかったりする</a>ので、どうにかこうにかラッパーを書いて当座はそれで凌ぐというのも手かもしれません…。</p>
<p>ちなみに、<code>char</code> と UTF-8 を使用するのであれば <code>&lt;regex&gt;</code> はそのまま使えるはずですが、その場合、 (Boost.Regex と同様に) <a href="http://blog.harapeko.jp/2010/09/22/utf-8-is-nice/" title="はらぺこ日誌? ブログアーカイブ ? UTF-8 もイマイチだが…"><code>&lt;regex&gt;</code> は UTF-8 を知らないので、マルチバイト特有の問題に悩まされることになる</a>でしょう。少なくとも日本語の文字に対する量指定子 (<q><code>あ+</code></q> とか <q><code>あ?</code></q> とか) は期待通りには動きません。</p>
<p>仮に、<code>&lt;regex&gt;</code> が <code>char32_t</code> で利用できる場合、先のサンプルは以下のようなコーディングになるでしょう。こういう風に組める日がいつか来るといいですね… <tt>(;_;)/</tt>。</p>
<pre>
#include &lt;iostream&gt;
#include &lt;algorithm&gt;
#include &lt;string&gt;
#include &lt;regex&gt;

#include &quot;EncodeString.hpp&quot;

using namespace std;

typedef basic_regex&lt;char32_t, regex_traits&lt;char32_t&gt;&gt; u32regex;
typedef match_results&lt;u32string::const_iterator&gt; u32smatch;


int main()
{
    u32string before = U&quot;てくまくまやこんてくまくまやこん むらやましゃちょうよ おおきなくまにな～ぁれ&quot;;
    u32string after;
    u32regex reg(U&quot;くま&quot;);
    u32smatch match;

    u32string textbuf = before;
    while (regex_search(textbuf, match, reg)) {
        after += match.prefix().str() + U&quot;ぱんだ&quot;;
        textbuf = match.suffix().str();
    }
    after += textbuf;

    cout &lt;&lt; &quot;before: &quot; &lt;&lt; EncodeString&lt;char32_t, chset_Utf32&gt;(before, chset_Utf8).getCharArray() &lt;&lt; endl;
    cout &lt;&lt; &quot;after: &quot; &lt;&lt; EncodeString&lt;char32_t, chset_Utf32&gt;(after, chset_Utf8).getCharArray() &lt;&lt; endl;

    return 0;
}
</pre>
]]></content:encoded>
			<wfw:commentRss>https://blog.harapeko.jp/2011/12/27/cpp11-unicode/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Boost.Regex の ICU 拡張と char32_t は相性がいいかも?</title>
		<link>https://blog.harapeko.jp/2011/09/21/boostregex-icu-with-char32_t/</link>
		<comments>https://blog.harapeko.jp/2011/09/21/boostregex-icu-with-char32_t/#comments</comments>
		<pubDate>Wed, 21 Sep 2011 02:27:05 +0000</pubDate>
		<dc:creator><![CDATA[村山 俊之]]></dc:creator>
				<category><![CDATA[技術メモ]]></category>
		<category><![CDATA[Boost]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[C++0x]]></category>
		<category><![CDATA[Unicode]]></category>
		<category><![CDATA[文字列処理]]></category>
		<category><![CDATA[正規表現]]></category>

		<guid isPermaLink="false">http://blog.harapeko.jp/?p=205</guid>
		<description><![CDATA[なんとなく Virtual Box から利用している Ubuntu のアップグレードなどをして、そこからなんと [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>なんとなく Virtual Box から利用している Ubuntu のアップグレードなどをして、そこからなんとなく「やっぱり Long Time Release 版の Ubuntu もテスト環境に持っておきたいよなぁ」などと思いつつ Virtual Box ディスクイメージを追加でこさえて、 Boost ライブラリのセットアップなどもしつつ動作チェックも兼ねて<a href="http://blog.harapeko.jp/2010/09/22/u32regex-bad-cast/" title="はらぺこ日誌» ブログアーカイブ » char32_t だと regex が使えない">昔書いた記事</a>なんぞを掘り起こしておりましたら、そこに書かれた内容に関連して、そういえば Boost.Regex も ICU ライブラリと組み合わせれば Unicode に対応できたはずだよなぁなどということが気になりだしてしまいまして、いろいろ試しているうちに、以下のようなサンプルコードが問題なく動作してしまうことを発見してしまったのでメモしておこうかと思った次第なのであります。ああ、なんだかこちらのブログも口調が個人ブログや普段の Twitter とかでのそれに似てきてしまいました <tt>(^_^;A</tt> 。<br />
<span id="more-205"></span></p>
<pre>
#include &lt;string&gt;
#include &lt;iostream&gt;
#include &lt;boost/regex.hpp&gt;
#include &lt;boost/regex/icu.hpp&gt;

using namespace std;

using boost::u32regex;
using boost::u32match;

int main()
{
        u32string text(U&quot;C++0x のせかいへようこそ!!&quot;);
        cout &lt;&lt; &quot;pre-modified text length = &quot; &lt;&lt; text.length() &lt;&lt; endl;
        u32string modified;
        u32regex reg(reinterpret_cast&lt;UChar32 const*&gt;(U&quot;せかい&quot;));
        u32match match;
        while (boost::regex_search(reinterpret_cast&lt;UChar32 const*&gt;(text.c_str()), match, reg)) {
                modified += u32string(reinterpret_cast&lt;char32_t const*&gt;(match.prefix().str().c_str())) + U&quot;世界&quot;;
                text = reinterpret_cast&lt;char32_t const*&gt;(match.suffix().str().c_str());
        }
        modified += text;
        cout &lt;&lt; &quot;modified text length = &quot; &lt;&lt; modified.length() &lt;&lt; endl;
        return 0;
}
</pre>
<p>とりあえず動作確認環境は以下の通りです。</p>
<ul>
<li>Ubuntu 11.04 + gcc 4.5.2 + Boost 1.42.0</li>
<li>Ubuntu 10.04 LTS + gcc 4.4.3 + Boost 1.40.0</li>
</ul>
<p>どちらでもコンパイルコマンドは以下で通ります (ソースファイルを <code>u32test.cpp</code> として保存した場合)。</p>
<pre>
$ g++ -std=c++0x -o u32test u32test.cpp -lboost_regex
</pre>
<p>実行してみると、置換前と置換後の文字数が正しくカウントされており、マッチングが期待通りに動作していることが確認できます。</p>
<pre>
$ ./u32test
pre-modified text length = 17
modified text length = 16
$ 
</pre>
<p>ただ、コードを見ていただければわかる通り、 <code>reinterpret_cast</code> の嵐であり、こうした書き方が C++0x 的にも Boost.Regex 的にも ICU 的にも Valid なのかはわかりません。また、現時点では Windows 環境 (MinGW + gcc 4.5 など) での動作確認は行っておりません。 ICU 拡張部分のヘッダを見る限り、内部で <code>wchar_t</code> を使っているので、 <code>wchar_t</code> が 16bits 境界になっている Windows では、バイトオーダーがひっくり返るなどの問題があって、もしかしたら正常に動かないかもしれません。</p>
<p>あくまで参考までと言いますか、将来的にはこういう感じの書き方ができるようになると良いなぁと言う程度の妄想、と捉えていただければと思います… <tt>m(_ _)m</tt></p>
<p>ちなみに、ここ最近ちっとも進んでいない otoco ですが、恐らく C++0x 自体の採用を見送る形になると思われます…。ただ、 Boost.Regex の ICU 拡張は有効利用できそうな気がしてきたので、こちらは利用することになるかもしれません。</p>
<p>Google の <a href="http://code.google.com/p/re2/">re2</a> に流れてしまいそうな悪寒もしてますが…。</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.harapeko.jp/2011/09/21/boostregex-icu-with-char32_t/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Perl の正規表現はリストコンテキストでキャプチャがないと (1) を返す</title>
		<link>https://blog.harapeko.jp/2011/09/01/perlre-list-nocapture/</link>
		<comments>https://blog.harapeko.jp/2011/09/01/perlre-list-nocapture/#comments</comments>
		<pubDate>Thu, 01 Sep 2011 01:20:24 +0000</pubDate>
		<dc:creator><![CDATA[村山 俊之]]></dc:creator>
				<category><![CDATA[技術メモ]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[正規表現]]></category>

		<guid isPermaLink="false">http://blog.harapeko.jp/?p=158</guid>
		<description><![CDATA[Perl で、 my @cap = $uri{$mkey} =~ /$ex_item-&#62;{match}{ [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Perl で、</p>
<pre>
my @cap = $uri{$mkey} =~ /$ex_item-&gt;{match}{$mkey}{pattern}/    or next EX_MATCH_LOOP;
@vars{@{$ex_item-&gt;{match}{$mkey}{vars}}} = @cap
    if exists $ex_item-&gt;{match}{$mkey}{vars} &amp;&amp; ref $ex_item-&gt;{match}{$mkey}{vars} eq 'ARRAY';
</pre>
<p>なんてコードを書いていて (何をやろうとしているのかは想像にお任せします… 別にプロプライエタリなコードじゃないし、いちいち擬似コード的に書き直すのも面倒なのでそのまま持って来ちゃいましたｗ)、ふと、ここでやっている正規表現のパターンにキャプチャが含まれていなかった場合、マッチするのに <code>or</code> の後に処理が流れてしまうことはないのかと疑問に思いました。<br />
<span id="more-158"></span><br />
結論としては、上記のコードに問題はないようです (まだテストしてないけど)。以下のように、スモールケースで試してみると、リストコンテキストではパターンにキャプチャがない場合でも空リストを返すのではなく、 <code>(1)</code>、すなわち値 <code>1</code> のみを持つリストを返してくれることが分かります。</p>
<pre>
$ perl -e '$x = "foo bar baz"; @s = $x =~ /bar/ or print "no match?\n"; print join(", ", @s), "\n"'
1
$ 
</pre>
<p>もちろん、キャプチャがある場合には、キャプチャリングされた値がリストとして返されます。</p>
<pre>
$ perl -e '$x = "foo bar baz"; @s = $x =~ /(b)(ar)/ or print "no match?\n"; print join(", ", @s), "\n"'
b, ar
$ 
</pre>
]]></content:encoded>
			<wfw:commentRss>https://blog.harapeko.jp/2011/09/01/perlre-list-nocapture/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>UTF-8 もイマイチだが…</title>
		<link>https://blog.harapeko.jp/2010/09/22/utf-8-is-nice/</link>
		<comments>https://blog.harapeko.jp/2010/09/22/utf-8-is-nice/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 14:55:16 +0000</pubDate>
		<dc:creator><![CDATA[村山 俊之]]></dc:creator>
				<category><![CDATA[技術メモ]]></category>
		<category><![CDATA[Boost]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[C++0x]]></category>
		<category><![CDATA[otoco]]></category>
		<category><![CDATA[Unicode]]></category>
		<category><![CDATA[文字列処理]]></category>
		<category><![CDATA[正規表現]]></category>

		<guid isPermaLink="false">http://blog.harapeko.jp/?p=138</guid>
		<description><![CDATA[UTF-32 が内部文字列に使えないことがわかったので、 UTF-8 を内部文字列に使用するというルールで l [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://blog.harapeko.jp/2010/09/22/u32regex-bad-cast/" title="はらぺこ日誌» ブログアーカイブ » char32_t だと regex が使えない">UTF-32 が内部文字列に使えないことがわかった</a>ので、 UTF-8 を内部文字列に使用するというルールで libiconv によるエンコーディング操作と Boost.Regex による正規表現の両方を同時に試すサンプルを作成してみました。</p>
<ul>
<li><a href="http://developer.harapeko.jp/trac/original/otoco/browser/trunk/sample/EncodeString.hpp">sample/EncodeString.hpp</a></li>
<li><a href="http://developer.harapeko.jp/trac/original/otoco/browser/trunk/sample/EncodeString.cpp">sample/EncodeString.cpp</a></li>
<li><a href="http://developer.harapeko.jp/trac/original/otoco/browser/trunk/sample/regex-test.cpp">sample/regex-test.cpp</a></li>
</ul>
<p>Makefile は作ってません＼(^O^)／。試してみたい人は頑張ってコンパイルしてねｗ</p>
<pre>
$ g++ -std=c++0x -o regex-test regex-test.cpp EncodeString.cpp -lboost_regex
</pre>
<p>まともな環境 (Linux + GCC4.5 とか) なら上記コマンドで通るはず。libiconv を (glibc に上書きする形で) インストールしている場合は <code>-liconv</code> を末尾に入れる必要があるかも。そして MinGW を使う場合は更にもう一工夫必要かも <tt>(((;/^^)/</tt><br />
<span id="more-138"></span><br />
さてこのプログラム、注目して頂きたいのは、<code>regex-test.cpp</code> の以下の行です。</p>
<pre>
        regex reg(u8"くま|川|(お)?魚");
</pre>
<p>正規表現を定義しているのですが、一文字でしかないはずの <code>"お"</code> がわざわざ丸括弧でくくってありますね。これが Perl で <code>use utf8;</code> していたり、 UTF-8 で JavaScript を書いていたりしているのであれば、不要な括弧です。</p>
<p>しかし、 Boost.Regex を UTF-8 で使用する場合には必要です。この括弧がなければ、 <code>"?"</code> は <code>"お"</code> の最終オクテットにしか適用されません。なぜなら、 Boost.Regex は UTF-8 なんて知らないので、 <code>"お"</code> が論理的には 1文字でしかない、なんてことは認識できないからです。</p>
<p>すなわち、</p>
<pre>
        regex reg(u8"くま|川|お?魚");
</pre>
<p>と書いてしまうと、<code>"お魚"</code> には hit しますが、 <code>"魚"</code> には hit しなくなってしまうのです。</p>
<p>otoco では、 MML コンパイラ機能において、プログラマブルマクロを定義できる機能を提供する予定です。具体的には Lua でマクロを定義し、そのマクロを用いて生成した MML をインライン展開できるようにする、といったものです (実際の所、言語に Lua を採用すべきか JavaScript を採用すべきか、はたまた Python を採用すべきかで迷っているところではあるのですが…)。</p>
<p>で、 (Lua を採用する場合には) 正規表現を用いた文字列加工を行う関数を提供するつもりでいるのですが (JavaScript とかだったら不要なんですけどね、言語機能にあるし)、仮に非 ASCII な文字 (列) を hit させようとする正規表現に <code>"?"</code> やら <code>"[</code>…<code>]"</code> やらが使われた場合、どう扱うべきなんだろう、といった辺りが悩みどころではあったりします…。</p>
<p>まぁなんにせよ、他に選択の余地もないので、とりあえず内部文字列は UTF-8 で実装するという方針でやっていくことにしようかと思います。前途多難じゃ… orz</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.harapeko.jp/2010/09/22/utf-8-is-nice/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Windows で Boost セットアップ</title>
		<link>https://blog.harapeko.jp/2009/07/13/boost-setup-for-windows/</link>
		<comments>https://blog.harapeko.jp/2009/07/13/boost-setup-for-windows/#comments</comments>
		<pubDate>Mon, 13 Jul 2009 01:24:02 +0000</pubDate>
		<dc:creator><![CDATA[村山 俊之]]></dc:creator>
				<category><![CDATA[技術メモ]]></category>
		<category><![CDATA[活動記録]]></category>
		<category><![CDATA[Boost]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[otoco]]></category>
		<category><![CDATA[Perl]]></category>
		<category><![CDATA[正規表現]]></category>

		<guid isPermaLink="false">http://blog.harapeko.jp/?p=85</guid>
		<description><![CDATA[Windows 環境で Boost ライブラリをセットアップしてみました。明日は Linux 環境でもセットア [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Windows 環境で Boost ライブラリをセットアップしてみました。明日は Linux 環境でもセットアップを行い、<a href="http://developer.harapeko.jp/trac/original/otoco/wiki/%E6%8A%80%E8%A1%93%E3%83%A1%E3%83%A2/Boost%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97">技術メモ</a>としてまとめる<a href="http://developer.harapeko.jp/trac/original/otoco/ticket/3">予定</a>です。</p>
<p>で、せっかくなので、試しに簡単なサンプルを作って動作確認をしてみました。</p>
<pre>
#include &lt;iostream&gt;
#include &lt;fstream&gt;
#include &lt;string&gt;

#include &lt;boost/regex.hpp&gt;

using namespace std;
using namespace boost;

void escapeHtml(const string &amp;src, string &amp;modified);

int main(int argc, char* argv[])
{
	for (int i = 1; i &lt; argc; i++)
	{
		ifstream fin(argv[i]);
		if (fin.bad() || fin.fail())
		{
			cerr &lt;&lt; argv[0] &lt;&lt; &quot;: Can't open &quot; &lt;&lt; argv[i] &lt;&lt; &quot;.&quot; &lt;&lt; endl;
			continue;
		}
		while (!fin.eof())
		{
			string line;
			getline(fin, line);
			string modified;
			escapeHtml(line, modified);
			cout &lt;&lt; modified &lt;&lt; endl;
		}
	}
	
	return 0;
}

void escapeHtml(const string &amp;src, string &amp;modified)
{
	modified.clear();
	sregex_iterator last_it;
	for (sregex_iterator it(src.begin(), src.end(), regex(&quot;[&lt;&gt;&amp;\&quot;]&quot;)); it != sregex_iterator(); it++)
	{
		modified += it-&gt;prefix().str();
		string sub = (*it)[0].str();
		switch (sub[0])
		{
			case '&lt;':	modified += &quot;&amp;lt;&quot;;		break;
			case '&gt;':	modified += &quot;&amp;gt;&quot;;		break;
			case '&amp;':	modified += &quot;&amp;amp;&quot;;	break;
			case '&quot;':	modified += &quot;&amp;quot;&quot;;	break;
			default:	assert(0);	break;
		}
		last_it = it;
	}
	modified += last_it == sregex_iterator() ? src : last_it-&gt;suffix().str();
}
</pre>
<p><a href="http://boost.cppll.jp/HEAD/libs/regex/doc/regex_iterator.html">Boost.Regex の regex_iterator</a> を用いたテストです。よーするに、コマンドに指定したファイルの HTML エスケープ処理を施してコンソールに書き出すプログラムです。</p>
<p>上記のプログラムを test.cpp などのファイル名で保存し、そのまま Visual Studio 2008 コマンドプロンプト上で</p>
<pre>
cl test.cpp
</pre>
<p>とやってみましたが、これだけではコンパイルできませんでした。どうやら、 Visual Studio のオプションダイアログでヘッダーファイルやライブラリの参照先ディレクトリを設定しても、その設定が参照されるのは Visual Studio の IDE からビルドを実行した場合のみのようです。あるいは、環境変数 INCLUDE や LIB を設定してあげればこれでコンパイルできるのかも知れません。その辺はまた追々調べてみますが、最終的には <code>.configure</code> に <code>--boost-prefix</code> といったようなオプションを設ける、といった形の対応になるのではないかとも思います。</p>
<p>ちなみに、これと同等の (しかもより確実に動作する) プログラムを Perl で記述すると、以下の通りになります (この書き方はしかし Unix 風環境限定ですが)。</p>
<pre>
#!/usr/bin/perl -p
s/[&lt;&gt;&amp;&quot;]/'&amp;'.{qw(&lt; lt &gt; gt &amp; amp &quot; quot)}->{$&amp;}.';'/eg;
</pre>
<p>うあー、やっぱりスクリプト言語は便利だなー (汗。</p>
<hr />
<div>2009年  7月 28日 火曜日 16:56:07 JST &#8211; <strong>追記</strong></div>
<p>egtra 様、ご指摘感謝です。仰る通り、 <code>string::getline()</code> を使った方がスマートなので、その通りに修正させて頂きました。</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.harapeko.jp/2009/07/13/boost-setup-for-windows/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
