サイトトップ

Director Flash 書籍 業務内容 プロフィール

Adobe Flash CS3 Professional ActionScript 3.0

□Tech 03 ECMAScript for XMLと正規表現

あまり派手さはないものの、ActionScript 3.0において、従来の2.0/1.0より格段に処理しやすくなったものとして、ECMAScript for XML(E4X)正規表現が挙げられます。これらの基本的な扱い方について、簡単にご紹介します。

03-01 ECMAScript for XML(E4X)
ECMAScript for XMLは、「E4X」と略称されます。これはECMAScript 3(Column 01「ECMAとECMAScript」参照)を拡張して、XMLのネイティブデータを扱うための仕様です。XMLデータを、きわめて柔軟に処理することができます。

Maniac! Tech03-001■ECMAScript for XML (E4X) Specification
E4Xの仕様は「ECMAScript for XML (E4X) Specification」として第2版が公開されています(<http://www.ecma-international.org/publications/standards/Ecma-357.htm>)。

[*筆者用参考]「ECMAScript for XML (E4X) 仕様邦訳

まず、XMLデータはスクリプト上で、つぎのようにタグ(<>)を使ってリテラル(Word 03-003「リテラル」参照)記述します。データ型の指定はXMLです。

var cs3_xml:XML = <cs3>
  <product suite="Web">
    <name>Flash</name>
    <price>699</price>
  </product>
  <product suite="Web">
    <name>Dreamweaver</name>
    <price>399</price>
  </product>
  <product suite="Design">
    <name>Photoshop</name>
    <price>649</price>
  </product>
  <product suite="Design">
    <name>Illustrator</name>
    <price>599</price>
  </product>
</cs3>;

XMLのノードは、ドット演算子(.)でその名前を指定して取得します。取出したノード群は、XMLListで型指定します。たとえば、上記XMLデータのproductノード群は、つぎのようにして得られます(図Tech03-001)。

var products:XMLList = cs3_xml.product;
trace(products);

このスクリプトにより、[出力]パネルにはつぎのように表示されます。

<product suite="Web">
  <name>Flash</name>
  <price>699</price>
</product>
<product suite="Web">
  <name>Dreamweaver</name>
  <price>399</price>
</product>
<product suite="Design">
  <name>Photoshop</name>
  <price>649</price>
</product>
<product suite="Design">
  <name>Illustrator</name>
  <price>599</price>
</product>
図Tech03-001■XMLデータからノード群を取得する

XMLデータにドット演算子(.)でノード名を指定すると、ノード群がXMLListインスタンスとして取得できる。

ノード群をもつXMLListインスタンスに対してさらに子ノード名を指定すれば、その子ノード群を抜出すことができます。

var names:XMLList = cs3_xml.product.name;
trace(names);

[出力]パネルにはつぎのように、指定した子ノード<name>のみに絞り込まれて表示されます。

<name>Flash</name>
<name>Dreamweaver</name>
<name>Photoshop</name>
<name>Illustrator</name>

要素名を条件として指定すれば、それに当てはまるノードを得ることもできます。条件は括弧()を使って記述します。たとえば、つぎのスクリプトは、<name>要素が"Flash"と等価という条件に合う<product>ノードを取得して[出力]します。

var product_flash:XMLList = cs3_xml.product.(name == "Flash");
trace(product_flash);

[出力]パネルには、<name>が"Flash"の<product>ノードが表示されます。

<product suite="Web">
  <name>Flash</name>
  <price>699</price>
</product>

属性は@を用いて指定します。要素名と同じように、条件として用いることもできます。たとえば、suite属性が"Web"の<product>ノード群は、つぎのスクリプトで取出すことができます。

var products_web:XMLList = cs3_xml.product.(@suite == "Web");
trace(products_web);

[出力]パネルには、suite属性として"Web"の指定されている<product>ノードが抜出されて表示されます。

<product suite="Web">
  <name>Flash</name>
  <price>699</price>
</product>
<product suite="Web">
  <name>Dreamweaver</name>
  <price>399</price>
</product>

03-02 正規表現(RegExpクラス)
RegExpクラスは、正規表現を処理します。「正規表現」(Regular Expression)とは、文字列のパターンを表現する記述です。RegExpインスタンスで指定したパターンを使って、文字列を調べることができます。また、Stringクラスのメソッドに引数として渡すことにより、文字列を操作することも可能です。

RegExpインスタンスは、RegExpクラスのコンストラクタを呼出して生成できるほか、以下のようにパターンをスラッシュ(/)で括ってリテラル記述することも可能です。リテラル記述の方が簡単で見やすいでしょう。

var 変数:RegExp = /パターン/

たとえば、"AS"という文字列をパターンとするRegExpインスタンスは、スラッシュで括って/AS/と記述すれば作成できます。RegExp.test()メソッドを使うと、引数に指定した文字列にパターンが含まれるかどうかを調べられます。つぎのスクリプトは、"Flashファイル(AS 3.0)"というテキストに文字列"AS"が含まれていることを確かめます。

var my_str:String = "Flashファイル(AS 3.0)";
var myPattern:RegExp = /AS/;
var bResult:Boolean = myPattern.test(my_str);
trace(bResult);   // 出力: true

Stringクラスのメソッドには、RegExpインスタンスのパターンを引数として指定できるものがあります。String.replace()メソッドの第1引数にRegExpインスタンスを渡すと、そのパターンに当てはまる文字列を第2引数の文字列と置換えます。

以下のスクリプトは、復帰文字"\r"を改行として用いた文字列に対して、String.replace()メソッドを使って、"\r"を"<br>に置換えます。String.replace()メソッドメソッドの第1引数には、RegExpインスタンス/\r/をパターンとして渡しています。

var my_str:String = "Flash\rDreamweaver\rPhotoshop\rIllustrator";
var myPattern:RegExp = /\r/;
var result_str:String = my_str.replace(myPattern, "<br>");
trace(result_str);

// 出力:
Flash<br>Dreamweaver
Photoshop
Illustrator

上記スクリプトで渡したRegExpインスタンスは、パターンに当てはまる最初の文字列のみを示す表現になります。したがって、String.replace()メソッドの置換結果も、最初の改行("\r")のみが文字列"<br>に変わり、あとの改行はそのまま残っています。パターンと一致する文字列すべてを指定したいときには、正規表現にg(global)フラグを添えます。

以下のスクリプトでは、正規表現にgフラグを加えましたので、String.replace()メソッドが参照する文字列中のすべての改行("\r")は、文字列"<br>"に置き換わります。

var myPattern:RegExp = /\r/g;   // gフラグを加える
var result_str:String = my_str.replace(myPattern, "<br>");
trace(result_str);   // 出力: Flash<br>Dreamweaver<br>Photoshop<br>Illustrator

[*イラスト候補●Tech03-001] 正規表現を使うと、パターンを指定して文字列が操作できる。

選択制御文字|を使うと、複数のパターンのいずれかひとつを対象とする指定ができます。

たとえば、テキストファイルの改行コードは、プラットフォームによって異なります。Windowsは復帰文字+改行文字("\r\n")、Macintoshが復帰文字("\r")、UNIXやLinuxは改行文字("\n")です。これらいずれのファイルの文字列であっても同じ改行コード、たとえば復帰文字("\r")に統一するためには、その文字列に対してString.replace()メソッドを、つぎのような正規表現の引数で呼出します。

var my_str:String = "Flash\nDreamweaver\r\nPhotoshop\rIllustrator";
var myPattern:RegExp = /\n|\r\n/g;
var result_str:String = my_str.replace(myPattern, "\r");
trace(result_str.split("\r"));   // 出力: Flash,Dreamweaver,Photoshop,Illustrator

このスクリプトは、復帰文字+改行文字("\r\n")あるいは改行文字("\n")を、復帰文字("\r")に置換えます。復帰文字("\r")単独であれば、そのまま変更しません。したがって、改行コードが、復帰文字("\r")に統一されます。ただし、その結果の確認には注意が必要です。

trace()関数に変更後の文字列を渡しても、[出力]パネルでは制御コード自体は表示されず、改行そのものになるため、改行コードが意図どおりに変更されたかどうかは確かめられません。そこで上記スクリプトでは、String.split()メソッド(Word Tech03-001)を利用しています。

Word Tech03-001■String.split()メソッド
つぎのシンタックスで、文字列を配列に変換して返します。

文字列.split(区切り文字:StringまたはRegExp):Array

参照する文字列を区切り文字でエレメントに分け、それらを格納した配列にして返します。

区切り文字に空文字列""または空の正規表現を指定すると、文字列をひと文字ずつのエレメントに分けた配列が返されます。区切り文字を指定しないと、文字列全体をひとつのエレメントとする配列が帰ります。

なお、引数に正規表現を使う場合には若干の注意があり、またオプションとして第2引数が指定できます。これらについては、[ヘルプ]の[ActionScript 3.0コンポーネントリファレンスガイド] > [String]の「String.split()」の項をお読みください。

このメソッドとは逆に、配列のエレメントを連結し、文字列に変換して返すメソッドとして、Array.join()があります。

区切り文字 ー 文字列(String型)または正規表現(RegExp型)を指定します。ただし、メソッドにおける引数の型指定は、かたちのうえでは任意(*)となっています。

String.split()メソッドは、参照する文字列を引数に指定された区切り文字でエレメントに分け、それらを納めた配列に変換して返します。そこで、上記スクリプトでは、統一されるべき復帰文字("\r")を区切り文字として、変更後の文字列にString.split()メソッドを適用しています。そして、その配列をtrace()関数で[出力]しています。その結果、配列エレメントが改行位置で分けられ、余分な改行が表れないことにより、正しく変更されたことが確かめられます。

CSV(カンマ区切り)ファイルを扱う場合など、テキストデータを最終的にエレメントに分けて配列に収めたい場合には、String.split()メソッドの区切り文字にも正規表現が使えます。

var my_str:String = "Flash\nDreamweaver\r\nPhotoshop\rIllustrator";
var myPattern:RegExp = /\n|\r\n|\r/g;
var result_array:Array = my_str.split(myPattern);
trace(result_array);   // 出力: Flash,Dreamweaver,Photoshop,Illustrator

繰返し制御文字?を使うと、その直前の項目が存在しない場合もパターンに含めることができます。ですから、上記スクリプトの正規表現は、つぎのように記述することも可能です。

var myPattern:RegExp = /\n|\r\n?/g;

CSV(カンマ区切り)ファイルは、1件(レコード)のデータを改行で区切り、その中の項目(フィールド)はカンマ(",")で分けます。同じ階層にある外部CSVファイル"test.csv"を読込んで、入れ子の配列に変換するフレームアクションは、以下のスクリプトTech03-001のようになります。改行で配列エレメントに分ける際、String.split()メソッドの引数に複数の改行コードに対応した上記正規表現を指定しています。

スクリプトTech03-001■外部CSVファイルをロードして入れ子の配列に変換する

// フレームアクション
var myLoader:URLLoader = new URLLoader();
var myRequest:URLRequest = new URLRequest("test.csv");
var result_array:Array;
myLoader.addEventListener(Event.COMPLETE, xParseCSV);
myLoader.load(myRequest);
function xParseCSV(eventObject:Event):void {
  var my_str:String = myLoader.data;
  var myPattern:RegExp = /\n|\r\n?/g;
  result_array = my_str.split(myPattern);
  var nLength:int = result_array.length;
  for (var i:int=0; i<nLength; i++) {
    var _str:String = String(result_array[i]);
    result_array[i] = _str.split(",");
  }
}

外部テキストファイルのロードについては、前章Tech 02-03「外部テキストファイルをロードして表示する」で説明しました。Loader.completeイベントのリスナー関数xParseCSV()内で、String.split()メソッドにより、まず文字列を改行区切りのレコードがエレメントとなった配列に変換しています。そして、さらにそのレコードひとつひとつをforループで、カンマ区切りのフィールドがエレメントとなる入れ子の配列に差替えています。

Tips Tech03-001■
入れ子の配列をtrace()関数で[出力]しても、親のエレメントも入れ子のエレメントも同じようにカンマ区切りのみで表示されるため、親子の区別がつきません(図Tech03-002)。これを判別するためには、親の配列エレメントをひとつひとつ[出力]する簡単な関数があるとよいでしょう。

図Tech03-002■[出力]パネルに表示された入れ子の配列

親のエレメントも入れ子のエレメントも、カンマ区切りで区別がつかない。

以下のスクリプトTech03-002は、引数に渡された配列エレメントを1行1行分けて[出力]パネルに表示します。なお、確認のため[出力]する行の初めには、入れ子の配列の長さを表示します(図Tech03-003)。

スクリプトTech03-002■配列のエレメント数とその内容を[出力]する関数定義

// フレームアクション
function xShowArrayElements(my_array:Array):void {
  var nLength:int = my_array.length;
  for (var i:int=0; i<nLength; i++) {
    trace(my_array[i].length, my_array[i]);
  }
}


図Tech03-003■親の配列エレメントを関数で1行1行[出力]する

行の先頭は入れ子の配列の長さとし、そのあとに親配列のエレメントである入れ子の配列を[出力]している。

選択制御文字|や繰返し制御文字?などは「メタ文字」と呼ばれ、特別な役割をもちます。正規表現には、さらに複数の文字を表す「メタシーケンス」などの特殊な文字があり、文字列の複雑なパターンを指定できます。たとえば、つぎのスクリプトは正規表現でメールアドレスのパターンを指定し、String.match()メソッドによりそのパターンに当てはまる文字列を配列に抜出します。

var my_str:String = "email:fumio@fumiononaka.com";
var myPattern:RegExp = /[\w.-]+@[\w.-]+\.[\w.-]+/g;
var result_array:Array = my_str.match(myPattern);
trace(result_array[0]);   // 出力: fumio@fumiononaka.com

上記スクリプトの正規表現で用いられた特殊な文字は、下表Tech03-001のとおりです。まず、[\w.-]は半角英数字または_(アンダースコア)、もしくは.(ドット)あるいは-(ハイフン)のうちのひと文字(以下「半角英数字等」と表記します)を表します。つぎに、+(プラス)は、その前に記述された半角英数字等が、ひと文字以上繰返す文字列を意味します。\.は、.(ドット)が特殊な文字ですので、それがエスケープされて普通の文字の.(ドット)を指します。

したがって、上記の正規表現で示されるメールアドレスのパターンは、半角英数字等の1文字以上の文字列の後に@が続き、その後にさらに半角英数字等の1文字以上の文字列、そして.(ドット)が必要で、最後にまた半角英数字等の1文字以上の文字列があるという指定になります。

表Tech03-001■正規表現で用いられる特殊な文字の一部
特殊な文字 説明
\ エスケープ文字です。メタ文字などの特殊な文字を、普通の文字として指定したいとき、その文字の前に記述します。
+ 直前の文字のパターンを1回以上繰返す指定です。
? 直前の文字のパターンを0回もしくは1回含む指定です。
[] 文字クラスを定義します。文字クラスは、ひとつの文字が取り得る文字パターンのリストを指定します。文字クラス内では、メタ文字のエスケープは不要です。
| 左側もしくは右側のどちらか一方のパターンを示す指定です。
\w 半角英数字(A〜Z、a〜z、0〜9)または_(アンダースコア)ひと文字の指定です。

なお、メタ文字やメタシーケンスなどの特殊な文字について詳しくは、[ヘルプ]の[ActionScript 3.0のプログラミング] > [正規表現の使用] > [正規表現のシンタックス] > [文字、メタ文字、およびメタシーケンス]をお読みください。

Maniac! Tech03-002■正規表現によるメールアドレスの判別
前掲スクリプトのメールアドレスの判別は、ごく簡易なものです。実際のメールアドレスには、\や!、/、!、%などの文字も使用できるようです。したがって、正確な判別には、メールアドレスの仕様を確認したうえで、かなり込入った指定が必要になります。

興味のある方は、ネットで「正規表現 メールアドレス」をキーワードに検索すると、詳しい情報が得られるでしょう。

[*筆者用参考] phpspot「正規表現:メールアドレスかどうか調べる」、正規表現のサンプル集「メールアドレスを検索する」、Webプログラマー+WebデザイナーなZARU日記「メールアドレスを正規表現で判定する方法」。

[*筆者用参考] akihiro kamijo「AS3と正規表現」および「Stringと正規表現」。

[Prev/Next]


作成者: 野中文雄
作成日: 2008年7月15日


Copyright © 2001-2008 Fumio Nonaka.  All rights reserved.