前のページ|次のページ

DATAステップでPerl正規表現を使用する

Perl正規表現の構文

Perl正規表現のコンポーネント

Perl正規表現は、メタ文字と呼ばれる文字と特殊文字で構成されます。照合を実行すると、SASはPerl正規表現で指定された部分文字列をソース文字列から検索します。メタ文字を使用すると、SASは特別なアクションを実行します。これには、強制的に特定の位置から照合を開始したり、特定の文字セットとの照合を実行したりするなどのアクションがあります。デフォルトの区切り文字はフォワードスラッシュのペアです。メタ文字と、それらのメタ文字に一致する値を次の2つの例に示します。
  • メタ文字\dを使用すると、0–9間の数字に一致します。
  • /\dt/を使用すると、文字列“Raleigh, NC 27506”中の数字に一致します。
PRXのメタ文字のリストは、Perl正規表現(PRX)のメタ文字テーブルにあります。メタ文字の完全なリストについては、Perlのドキュメントを参照してください。

文字列で一致を検索するための基本的な構文

ソース文字列中で一致した値の位置を検索するには、PRXMATCH関数を使用します。PRXMATCHの一般的な形式を次に示します。
/search-string/source-string/
次の例では、PRXMATCH関数を使用してsearch-stringの位置をsource-stringの中から検索します。
prxmatch('world', 'Hello world!');
worldは文字列Hello world!の7番目の位置に出現するため、PRXMATCHの結果は値7です。

テキストの検索と置換の基本的な構文

テキストの検索と置換の基本的な構文は次の形式です。
s/regular-expression/replacement-string/ 
次の例では、PRXCHANGE関数を使って置換を行う方法を示しています。
prxchange('s/world/planet/', 1, 'Hello world!'); 
引数
s
置換に使用するメタ文字を指定します。
world
正規表現を指定します。
planet
worldを置換する値を指定指定します。
1
1回の一致検出で検索を終了することを指定します。
Hello World!
検索するソース文字列を指定します。
置換の結果はHello planetとなります。

テキストの検索と置換の基本的な構文を使用するもう1つの例

もう1つの例で、PRXCHANGE関数を使用して値Jones, FredFred Jonesに変更します。
prxchange('s/(\w+), (\w+)/$2 $1/',-1, 'Jones, Fred');
この例では、Perl正規表現はs/(\w+), (\w+)/$2 $1です。一致の検索回数は–1です。ソース文字列は'Jones, Fred'です。値–1は、ソースの末尾に到達するまで一致したパターンを置換し続けることを指定します。
このPerl正規表現は次の要素に分けられます。
s
置換の正規表現を指定します。
(\w+)
1つ以上の単語文字(英数字とアンダースコア)に一致します。かっこは、キャプチャバッファ1に値を格納することを示します。
,<空白>
カンマと空白1つに一致します。
(\w+)
1つ以上の単語文字(英数字とアンダースコア)に一致します。かっこは、キャプチャバッファ2に値を格納することを示します。
/
正規表現と置換文字列の間の区切り文字列です。
$2
キャプチャバッファ2の値を置換する置換文字列部分です。この例ではカンマの後の単語で、結果に置換文字列を配置します。
<空白>
結果に空白を配置します。
$1
キャプチャバッファ1を結果に配置します。この例では、カンマの前の単語です。

テキストの置換

次の例では\uメタ文字と\Lメタ文字を使用し、MCLAURENの2番目の文字を小文字に置換します。
data _null_;
   x = 'MCLAUREN';
   x = prxchange("s/(MC)/\u\L$1/i", -1, x);
   put x=;
run;
次の出力がログに書き込まれます。
x=McLAUREN

例1:データの検証

文字列内に文字パターンが存在するかを検証できます。たとえば、文字列に正しい形式の電話番号が含まれているかどうかを調べて確認できます。この種のテストをデータ検証と呼びます。
電話番号のリストを検証する例を次に示します。有効な電話番号の形式は、(XXX) XXX-XXXXまたはXXX-XXX-XXXXのいずれかです。
data _null_;  1
   if _N_ = 1 then 
      do;  
         paren = "\([2-9]\d\d\) ?[2-9]\d\d-\d\d\d\d";  2
         dash = "[2-9]\d\d-[2-9]\d\d-\d\d\d\d";  3
         expression = "/(" || paren || ")|(" || dash || ")/";   4
         retain re; 
         re = prxparse(expression);  5
         if missing(re) then  6
            do;
               putlog "ERROR: Invalid expression " expression;  7
               stop;
            end;     
      end; 

length first last home business $ 16;
input first last home business;

   if ^prxmatch(re, home) then  8
      putlog "NOTE: Invalid home phone number for " first last home;

   if ^prxmatch(re, business) then  9
      putlog "NOTE: Invalid business phone number for " first last business;

   datalines;   
Jerome Johnson (919)319-1677 (919)846-2198 
Romeo Montague 800-899-2164 360-973-6201
Imani Rashid (508)852-2146 (508)366-9821 
Palinor Kent . 919-782-3199
Ruby Archuleta . . 
Takei Ito 7042982145 .
Tom Joad 209/963/2764 2099-66-8474
;
run;
次の項目は、上記のDATAステップで番号が付けられている行に対応しています。
1 DATAステップを作成します。
2 (XXX)XXX-XXXXに一致する電話番号を識別するPerl正規表現を記述し、変数PARENを割り当てて結果を保持します。次の構文要素を使用してPerl正規表現を記述します。
\( 市外局番の開始かっこに一致します。
[2–9] 市外局番の最初の番号である数字2–9に一致します。
\d 市外局番の2番目の番号である数字に一致します。
\d 市外局番の3番目の番号である数字に一致します。
\) 市外局番の閉じかっこに一致します。
<space>? 直前の部分表現である空白に0回または1回一致します。Perl正規表現では、空白に意味があります。これらは検索対象のテキストの空白に一致します。この例のように、疑問符の直前に空白があると、電話番号のこの位置の空白ゼロ個または1個に一致するパターンとなります。
3 XXX-XXX-XXXXに一致する電話番号を識別するPerl正規表現を記述し、変数DASHを割り当てて結果を保持します。
4 (XXX)XXX-XXXXとXXX—XXX—XXXXに一致する正規表現を連結するPerl正規表現を記述します。連結することで、両方の電話番号形式を1つの正規表現で検索できるようになります。
PARENとDASHの正規表現はかっこ内に配置されています。PARENとDASHの間にあるメタ文字の棒(|)は、コンパイラに対していずれかのパターンとの一致を指示します。パターン全体を囲むスラッシュは、正規表現の開始位置と終了位置をコンパイラに伝えます。
5 Perl正規表現をPRXPARSEに渡し、表現をコンパイルします。PRXPARSEはコンパイルされたパターンに対して値を返します。他のPerl正規表現の関数とCALLルーチンで値を使用し、コンパイルされたPerl正規表現を使った処理をSASで実行できます。
6 MISSING関数で正規表現が正常にコンパイルされたかどうかを確認します。
7 PUTLOGステートメントを使用し、正規表現がコンパイルされなかった場合はエラーメッセージをSASログに書き込みます。
8 有効な自宅電話番号を検索します。PRXMATCHはPRXPARSEからの値を検索テキストと合わせて使用し、検索テキストで正規表現が検出された位置を返します。自宅電話番号との一致がない場合、PUTLOGステートメントはSASログにメモを書き込みます。
9 有効な会社電話番号を検索します。PRXMATCHはPRXPARSEからの値を検索テキストと合わせて使用し、検索テキストで正規表現が検出された位置を返します。会社電話番号との一致がない場合、PUTLOGステートメントはSASログにメモを書き込みます。
データの検証からの出力
NOTE:Invalid home phone number for Palinor Kent NOTE:Invalid home phone number for Ruby Archuleta NOTE:Invalid business phone number for Ruby Archuleta NOTE:Invalid home phone number for Takei Ito 7042982145 NOTE:Invalid business phone number for Takei Ito NOTE:Invalid home phone number for Tom Joad 209/963/2764 NOTE:Invalid business phone number for Tom Joad 2099-66-8474

例2:テキストの一致と置換

この例では、Perl正規表現を使用して一致を検索し、一致した文字を他の文字に置換します。PRXPARSEで正規表現をコンパイルした後、PRXCHANGEで一致を検索して置換を実行します。ここでは、小なり記号のすべての出現を&lt;に置換します。これはテキストをHTMLに変換するときに一般的に行われる置換処理です。
data _null_;  1
   input;  2
   _infile_ = prxchange('s/</&lt;/', -1, _infile_);  3
   put _infile_;  4
   datalines;  5
x + y < 15
x < 10 < y
y < 11
;
run;
次の項目は、上記のDATAステップで番号が付けられている行に対応しています。
1 DATAステップを作成します。
2 SAS変数を作成しないで、入力バッファに入力データレコードを入れます。
3 PRXCHANGEルーチンを呼び出し、パターンによる置換を実行します。正規表現の形式はs/regular-expression/replacement-text/です。正規表現の前のsは、これが置換正規表現であることを示します。–1はPRXCHANGEに渡される特別な値で、置換できるものはすべて置換することを示します。
4 PUTステートメントの_INFILE_オプションを使用し、現在の出力行をログに書き込みます。
5 入力ファイルを識別します。
テキストの置換からの出力
x + y &lt; 15 x &lt; 10 &lt; y y &lt; 11
PRXCHANGEに正規表現を渡して結果を返すことができるため、PROC SQLクエリからPRXCHANGEを呼び出せます。次のクエリは、前述の例と同じ文字置換を行う列を作成します。クエリは入力テーブルからtext_linesを読み込み、列lineのテキストを置換し、結果をhtml_lineという名前の列に配置します。
proc sql;
   select prxchange('s/</&lt;/', -1, line)
   as html_line
   from text_lines;
quit;

例3:文字列から部分文字列を抽出する

Perl正規表現を使用すれば、文字列からテキストを検索し、簡単に抽出できます。この例では、DATAステップでノースカロライナ州の会社電話番号のサブセットを作成します。このプログラムは市外局番を抽出し、ノースカロライナ州の市外局番のリストとの照合を行います。
data _null_;  1
   if _N_ = 1 then 
      do; 
         paren = "\(([2-9]\d\d)\) ?[2-9]\d\d-\d\d\d\d";  2 
		      dash = "([2-9]\d\d)-[2-9]\d\d-\d\d\d\d";  3 
         regexp = "/(" || paren || ")|(" || dash || ")/";  4
         retain re; 
         re = prxparse(regexp);  5
         if missing(re) then  6
            do;
               putlog "ERROR: Invalid regexp " regexp;  7
               stop;
            end;     
 
         retain areacode_re;
         areacode_re = prxparse("/828|336|704|910|919|252/");  8
         if missing(areacode_re) then 
            do;
               putlog "ERROR: Invalid area code regexp";
               stop;
            end;
      end; 

   length first last home business $ 25;
   length areacode $ 3;
   input first last home business;

   if ^prxmatch(re, home) then  
      putlog "NOTE: Invalid home phone number for " first last home;

   if prxmatch(re, business) then  9
      do;
         which_format = prxparen(re);  10
         call prxposn(re, which_format, pos, len);  11
         areacode = substr(business, pos, len); 
         if prxmatch(areacode_re, areacode) then  12
            put "In North Carolina: " first last business;
      end;
      else
         putlog "NOTE: Invalid business phone number for " first last business;
   datalines; 
Jerome Johnson (919)319-1677 (919)846-2198 
Romeo Montague 800-899-2164 360-973-6201
Imani Rashid (508)852-2146 (508)366-9821 
Palinor Kent 704-782-4673 704-782-3199
Ruby Archuleta 905-384-2839 905-328-3892 
Takei Ito 704-298-2145 704-298-4738
Tom Joad 515-372-4829 515-389-2838
;
1 DATAステップを作成します。
2 (XXX)XXX-XXXXに一致する電話番号を識別するPerl正規表現を記述し、変数PARENを割り当てて結果を保持します。次の構文要素を使用してPerl正規表現を記述します。
\( 市外局番の開始かっこに一致します。開始かっこは部分一致の開始を表します。
[2–9] 数字2–9に一致します。
\d 市外局番の2番目の番号である数字に一致します。
\d 市外局番の3番目の番号である数字に一致します。
\) 市外局番の閉じかっこに一致します。閉じかっこは部分一致の終了を表します。
? 直前の部分表現である空白に0回または1回一致します。Perl正規表現では、空白に意味があります。これらは検索対象のテキストの空白に一致します。この例のように、疑問符の直前に空白があると、電話番号のこの位置の空白ゼロ個または1個に一致するパターンとなります。
3 XXX-XXX-XXXXに一致する電話番号を識別するPerl正規表現を記述し、変数DASHを割り当てて結果を保持します。
4 (XXX)XXX-XXXXとXXX—XXX—XXXXに一致する正規表現を連結するPerl正規表現を記述します。連結することで、両方の電話番号形式を1つの正規表現で検索できるようになります。
PARENとDASHの正規表現はかっこ内に配置されています。PARENとDASHの間にあるメタ文字の棒(|)は、コンパイラに対していずれかのパターンとの一致を指示します。パターン全体を囲むスラッシュは、正規表現の開始位置と終了位置をコンパイラに伝えます。
5 Perl正規表現をPRXPARSEに渡し、表現をコンパイルします。PRXPARSEはコンパイルされたパターンに対して値を返します。他のPerl正規表現の関数とCALLルーチンで値を使用し、コンパイルされたPerl正規表現を使った処理をSASで実行できます。
6 MISSING関数で正規表現がエラーなしにコンパイルされたかどうかを確認します。
7 PUTLOGステートメントを使用し、正規表現がコンパイルされなかった場合はエラーメッセージをSASログに書き込みます。
8 有効なノースカロライナ州の市外局番を文字列から検索するPerl正規表現をコンパイルします。
9 有効な会社電話番号を検索します。
10 PRXPAREN関数でどちらの部分一致を使うかを判定します。PRXPARENは一致した最後の部分一致を返します。市外局番が(XXX)形式に一致すると、PRXPARENは値2を返します。市外局番がXXX形式に一致すると、PRXPARENは値4を返します。
11 PRXPOSNルーチンを呼び出し、部分一致の位置と長さを取得します。
12 PRXMATCH関数で市外局番が正しいノースカロライナ州の市外局番かどうかを判定し、ログへオブザベーションを書き込みます。
文字列からの部分文字列抽出の出力
In North Carolina:Jerome Johnson (919)846-2198 In North Carolina:Palinor Kent 704-782-3199 In North Carolina:Takei Ito 704-298-4738

例4:文字列から部分文字列を抽出するもう1つの例

この例では、位置変数と長さ変数のかわりに、PRXPOSN関数を元の検索テキストに渡します。PRXPOSNは一致したテキストを返します。
data _null_;  1
   length first last phone $ 16;
   retain re;
   if _N_ = 1 then do;  2
      re=prxparse("/\(([2-9]\d\d)\) ?[2-9]\d\d-\d\d\d\d/");  3
   end;

   input first last phone & 16.;
   if prxmatch(re, phone) then do;  4
      area_code = prxposn(re, 1, phone);  5
      if area_code ^in ("828" 
                                  "336"
                                  "704"
                                  "910"
                                  "919" 
                                  "252") then
         putlog "NOTE: Not in North Carolina: "
                      first last phone;   6
    end;
   datalines;  7
Thomas Archer    (919)319-1677
Lucy Mallory       (800)899-2164
Tom Joad              (508)852-2146
Laurie Jorgensen  (252)352-7583
;
run;
次の項目は、上記のDATAステップで番号が付けられている行に対応しています。
1 DATAステップを作成します。
2 これが最初のレコードの場合、reの値を検索します。
3 パターンマッチングを行うPerl正規表現を記述します。次の構文要素を使用してPerl正規表現を記述します。
/ 正規表現の開始区切り文字です。
\( 次の文字入力を文字またはリテラルに指定します。
( 部分一致の開始を表します。
[2–9] 数字2–9に一致し、市外局番の最初の番号を識別します。
\d 市外局番の2番目の番号である数字に一致します。
\d 市外局番の3番目の番号である数字に一致します。
\) 市外局番の閉じかっこに一致します。閉じかっこは部分一致の終了を表します。
? 直前の部分表現である空白に0回または1回一致します。Perl正規表現では、空白に意味があります。空白は検索対象のテキストの空白に一致します。この例のように、疑問符の直前に空白があると、電話番号のこの位置の空白ゼロ個または1個に一致するパターンとなります。
|| 連結演算子です。
[2–9] 数字2–9に一致し、7桁の電話番号の最初の番号を識別します。
\d 7桁の電話番号の2番目の番号である数字に一致します。
\d 7桁の電話番号の3番目の番号である数字に一致します。
市外局番の後の電話番号の最初の3つの数字と最後の4つの数字の間のハイフンです。
\d 7桁の電話番号の4番目の番号である数字に一致します。
\d 7桁の電話番号の5番目の番号である数字に一致します。
\d 7桁の電話番号の6番目の番号である数字に一致します。
\d 7桁の電話番号の7番目の番号である数字に一致します。
/ 正規表現の終了区切り文字です。
4 文字列が開始する位置を返します。
5 市外局番が開始する位置を識別します。
6 リストから市外局番を検索します。市外局番が有効なノースカロライナ州の番号でない場合、PUTLOGステートメントを使用してSASログにメモを書き込みます。
7 入力ファイルを識別します。
文字列からの部分文字列抽出の出力
NOTE:Not in North Carolina:Lucy Mallory (800)899-2164 NOTE:Not in North Carolina:Tom Joad (508)852-2146
前のページ|次のページ|ページの先頭へ