こんにちは、高木です。
またまたPHPでC言語やC++の前処理を行う話題です。これまで何度か必要なときがあったのですが、議論の本質ではないと避けてきた、文字リテラルや文字列リテラルの生成についてそろそろ取り上げたいと思います。今回はC言語とC++に共通の内容になります。
今回は難しいことは避けて、単純なエスケープだけにしようと思います。よって、生文字リテラルは扱いません。u8, u, Uといったプレフィックスも直接は扱いませんので、必要ならPHPの開きタグの直前にプレフィックスを書くことで対応する必要があります。
それでは、まずは1文字のエスケープからです。
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?php function escape_char(string $c) : string { $c = $c[0]; switch ($c) { case "\a": $c = '\a'; break; case "\b": $c = '\b'; break; case "\f": $c = '\f'; break; case "\n": $c = '\n'; break; case "\r": $c = '\r'; break; case "\t": $c = '\t'; break; case "\v": $c = '\v'; break; case "'": $c = "\\'"; break; case '"': $c = '\"'; break; case "\\": $c = '\\'; break; } return $c; } ?> |
escape_char関数は、1文字をエスケープします。引数$cが文字列かどうかのチェックはしていませんが、必要ならis_stringでチェックした方がいいかもしれませんね。一応、$cが複数文字からなる文字列の場合を想定して、最初に先頭文字を取り出しています。このescape_char関数を下請けとして、文字リテラルと文字列リテラルを生成していきます。
次は文字リテラルを生成する関数を作ります。
0 1 2 3 4 5 6 7 8 |
<?php function char_literal(string $c) : string { $c = escape_char($c); return "'$c'"; } ?> |
このchar_literal関数で文字リテラルを生成することができます。内容は大したことなくて、エスケープした文字を単に一重引用符で囲んでいるだけです。
次に文字列リテラルを生成する関数です。
0 1 2 3 4 5 6 7 8 9 10 |
<?php function string_literal(string $s) : string { $r = '"'; $r .= implode(array_map('escape_char', str_split($s))); $r .= '"'; return $r; } ?> |
こちらも1文字ずつエスケープして二重引用符で囲んだだけです。せっかくですのでPHPらしく、いくつかのビルトイン関数を組み合わせてみました。まず、str_split関数で文字列を1文字ずつ格納した配列に分解しています。次に、array_map関数を使って、その配列の全要素に対してescape_char関数を呼び出した配列を作っています。そして、implode関数で配列の全要素を結合して1つの文字列にしています。最後に二重引用符で囲んでできあがりです。
PHPの文法はC言語によく似ていますので、C言語と同じように自分でループを書いてもかまわないのですが、たくさんのビルトイン関数が用意されているので上手に使うと実装が楽になります。できれば、C言語やC++でもPHPのビルトイン関数を使いたいものです。C言語はちょっと無理がある気がしますが、C++ならある程度はできるかもしれませんね。