JavaScriptとPHPでの特殊アルファベット文字の扱い

これは元々2010/03/05にAmebloに投稿した記事です。

F1 2010年シーズン開幕

数年続いた強豪2,3チームによる独占安定(故にそれほど面白く無い)シーズンから一変し、
新興チームの興隆や上位チームの実力拮抗により、非常に面白い展開となったF1 2009シーズン。

その2009年シーズを経て迎えた2010年シーズンは、
有力ドライバーの移籍などもあり否が応にもさらに注目されます。
そこで、今年度も面白い展開となるのではという期待を込めて、BlogaraでもF1選手権 2010のテーマを追加しました。

多くのチームやドライバーはNewsフィード配信や、Twitter
あるいはブログでは有りませんがFacebookを利用した情報発信を盛んに行っていますので、
Blogaraで取り上げる意義があるテーマとも言えます。


特殊アルファベット文字

F1には欧州や南米を中心とし数多くの非英語圏ドライバーが参戦していますので、
# というより英語圏ドライバーの方が少数ですが
a-Zの基本的なアルファベットで表記出来ない名前もそれなりに存在します。

そこでこの機会に、ドイツ語のウムラウトなど、
各種言語で一般に使われる特殊アルファベット(ダイアクリティカルマーク付きなど)
もアルファベット表記の名前として許可するような変更を行います。


3種類の名前表記

Blogaraでのメンバー(個人/団体/グループ)名表記では、
任意の名前(name)、カタカナ表記のフリガナ(fname)、アルファベット表記の名称(aname)
の3パターンが存在します。


任意の名前は、実際にクライアント側で(フォントが用意されて)表示出来るか否かに関係無く、
Unicodeで定義される数多くの文字を許容しますが、
Blogaraは現在日本語を主とするサービスですので、非日本語の名称ならば基本的にカタカナで表記を行っています。

フリガナは、ヰヵなど利用頻度が少ない文字も含め、全角(fullwidth)カタカナでの表記となります。

そしてアルファベット表記の名称は、
所謂7bit ASCIIコード帯に存在するa-Zの基本的なアルファベット文字(それとハイフン)だけを許可していました。


Blogaraは、サーバー/クライアント側双方でUnicode(UTF-8)ベースのシステムですので、
(非サロゲートペア帯の)Unicodeで定義される文字なら特に何のひねりも無く利用出来ます。
その為、その殆どがUnicodeで定義されると思われる特殊アルファベット文字への対応も簡単です。
# 逆に言うとUnicodeで定義されていない特殊アルファベット文字には対応しません。

勝手に定義した特殊アルファベット文字のような言葉で一括りに表現していますが、
実際には各言語でユニークな文字、あるいは各言語間で微妙に異なる数多くの文字が存在します。
そこで今回は、Unicode 5.2 Character Code ChartsのLatin-1 Supplementの一部からLatin Extended-Bの範囲まで、
U+00C0からU+024Fまでを(こちらの独断と偏見により)特殊アルファベット文字として扱う事にします。


クライアント側(JavaScript)での対応

FormControlへの追加変更

Blogara管理画面でのメンバー登録は、通常のWebアプリと同様にHTMLの入力フォームで行う形となりますが、
JavaScriptによりWebフォームに機能追加するFormControlを利用していますので、
その機能を利用した入力値の検証と変換が可能となります。

アルファベット名称を記入する項目には、
1. 全角文字を半角(halfwidth)に変換
2. a-Zのアルファベットと数値と半角スペース以外を削除
という強制変換が設定されていますので、
この2.に、特殊アルファベット文字も非削除文字として扱う条件を加えます。


正規表現による制限

この指定文字種別以外の文字を削除する処理は、正規表現を利用した一括変換を行います。
実際の正規表現指定は下記のようなidとパターンの組み合わせで記述していますが、
ここにU+00C0からU+024Fまでの特殊アルファベット文字帯をlatinExとして追加します。

Du.Type = new Hash({
  CodePattern: {
    alpha: 'a-zA-Z',
    number: '\\d',
    alnum: 'a-zA-Z\\d',
    latinEx: '\\u00c0-\\u024f',
    spaceH: '\\u0020',

アルファベット表記の名称(aname)のFormControlでの指定では、

'aname':{require:true, force:Du.Force.Ja.setForces(['df_ftoh',
  {id:'df_purge',opt:{code:['alnum','latinEx','spaceH'],except:'\-'}},'df_space']), 
  type:Du.Type.setTypes([{id:'dt_limit',opt:{'max':80}}])},

のようになっていますので、
この指定文字種以外を削除する設定(dt_purge)で指定されるalnum,latinEx,spaceH正規表現パターンを
初期化処理時にRegExpオブジェクトとして生成します。

new RegExp( '[^'+regStr+']', 'g' );

後は、各入力値チェック処理時に上記のRegExpを使ったreplace(変換後文字列に空文字を指定)を適用します。


サーバー側(PHP)での対応

一般のWebアプリでは、
入力値の検証や加工はクライアント側だけでは無くサーバー側にも実装されている必要が有ります
しかし、今回のように社内(あるいは許可を得た限られた人間)だけで利用するシステムでは、
クライアント側でのJavaScriptの実行を必須と規定していれば、
サーバー側のPHPに文字種別による削除の実装が絶対に必要という訳ではありません。

が、一種のフールプルーフ目的や、今後WebAPI経由などのでのデータ取得時にも適応可能とする為に、
サーバー側スクリプトにも強制変換や指定文字種以外の削除コードを実装しています。


TextControlへの追加変更

サーバー側スクリプトでの非許可文字種以外の削除は、PHPでのカタカナ/ひらがなのローマ字変換でも言及した、
文字列操作クラスであるTextControlに追加実装を行います。

サーバー側PHPによる文字種別による削除においても、
基本的には、クライアント側と同様に正規表現による一括変換となります。
ここでも特殊アルファベット文字指定としてCNV_MD_LATINEXのような正規表現パターンを追加し、
preg_replaceにて指定文字帯以外を削除します。
# ソースコードUTF-8なので、À-ɏのような全ての環境で表示される訳では無い文字を利用していますが、
# 問題になるようなら(というより気持ち悪いのであれば)文字参照指定から文字に変換しての指定で。
# html_entity_decode('À',ENT_NOQUOTES,'UTF-8').'-'.html_entity_decode('ɏ',ENT_NOQUOTES,'UTF-8');

if ( $mode&CNV_MD_ALPHA ) $reg .= 'a-zA-Z';
if ( $mode&CNV_MD_NUM ) $reg .= '\d';
if ( $mode&CNV_MD_LATINEX ) $reg .= 'À-ɏ';
return preg_replace( '/[^'.$reg.']/u', '', $str );

結果

今回行った、特殊アルファベット文字をアルファベット表記の名称として利用出来るようにする変更により、
Nico HÜLKENBERGや、 Sébastien BUEMIのような名前も登録可能となり、これにてひとまず完了となります。


参考資料

Unicode 5.2 Character Code Charts
Wikipedia: ダイアクリティカルマーク