2018年10月9日火曜日

「=:」を使った前方一致による比較と落とし穴





文字列の比較で使える「=:」を紹介します。
非常に重要な性質・注意点も含めて紹介していきます。



簡単な例


Sample data
data TEST;
length X $3.;
input X;
cards;
ab
abc
cab
;




data OUT1;
    set TEST;
    if X =: "ab" then FLG1=1;
run;



変数Xが "ab" で始まる値かどうか、という比較を行っています。


詳しく説明すると、「=:」の両辺に指定した変数または文字列のうち、LENGTHが大きい方は、LENGTHが小さい方の長さに切り捨てて比較を行ないます。


ここでいうLENGTHとは以下を指します。
 文字列の場合 

文字列の長さ」
 変数の場合

固定長の文字変数」の場合
「文字列と末尾の空白を含む長さ(つまり変数に定義した長さ)」
 
「固定長の文字変数」以外では「=:」がうまく機能しないので、
 使用しないで下さい(詳細も割愛)




上の例では、「X =: "ab"」で、
・左辺に指定した変数Xに定義されたlengthは「3」
・右辺に指定した "ab" は2バイトなのでlengthは「2」

この2つのlengthで小さいのは「2」なので、左辺の変数値を2バイトに切り捨てると以下の通り。

ab → ab
abc → ab
cab → ca

この切り捨てた値と右辺の "ab" がイコールか否か、という判定を行います。






注意が必要な例



data OUT2;
    set TEST;
    if X =: "abcd" then FLG1=1;
run;



「X =: "abcd"」で
・左辺の変数Xに定義されたlengthは「3」、
・右辺の "abcd" は4バイトなのでlengthは「4」、

lengthが小さいのは「3」なので、右辺の文字 "abcd" を3バイトで切り捨てると "abc" となります。


この "abc" が変数Xとイコールか否か、という判定を行います。
この切り捨てルールを知らないと、一見「変数Xが "abcd" で始まる値かどうか」と思ってしまいがちですが、間違いです!





今回の例のデータでもし「変数Xが "abcd" で始まる値かどうか」を判定したいなら、以下のように他の方法を使ったほうが安全です。
(以下で使用しているINDEX関数とFIND関数は両方ともシングルバイト専用の関数で日本語等のマルチバイトには対応していないので注意)

data OUT3;
    set TEST;
    if index( X, "abcd" )=1 then FLG1=1;    * 方法1 ;
    if find( X, "abcd" )=1 then FLG2=1;       * 方法2 ;
run;




0 件のコメント:

コメントを投稿