ラベル 関数: SUBSTR の投稿を表示しています。 すべての投稿を表示
ラベル 関数: SUBSTR の投稿を表示しています。 すべての投稿を表示

2019年5月16日木曜日

SUBSTR vs SUBSTRN




以下記事で「SUBSTRN関数」を紹介しました。
「文字列を抽出するSUBSTRN関数」


同じような機能で「SUBSTR関数」ってのもあり、皆さんはよくこちらを使うと思います。
では「SUBSTR関数」と「SUBSTRN関数」がどう違うのか、比較してみたいと思います。




基本構文


SUBSTR( Variable, Start, Length )
SUBSTRN( Variable, Start, Length )

  • Variable … 対象変数 or 対象文字
  • Start      … 何バイト目から抽出を開始するか
  • Length   … 抽出するバイト数(省略するとStart以降のすべての文字が抽出される)
  • Start と Length は「バイト数」で指定
  • シングルバイト文字専用の関数です。日本語などのマルチバイト文字には対応していません




1. 「SUBSTR」にしかない機能


  • 文字変数に対して、指定した位置の文字を置換する事ができる(「SUBSTR関数の小技」でも紹介)
data test;
    length x $3.;
    x = "abc";
    substr( x, 2, 1 ) = "X";
run;

ただし、2バイトを3バイトの文字に置き換え、みたいな異なる長さへの置換は出来ないので注意(詳細は上のリンク記事をご確認下さい)




2. 「SUBSTRN」にしかない機能


  • 第1引数に数値変数を指定した場合、自動でBEST32形式の文字値に変換されて、抽出が行われる。
data test2;
    length x 8. y $10.;
    x = 123;
    y = substrn( x, 2, 2 );
run;

ちなみに数値を文字値に変換すると「                             123」みたいに前方に余計な半角スペースが入ってしまう事があるけど、SUBSTRNは文字値に変換する時にこの余計な半角スペースも取り除いてくれます。




3. 変数のLENGTHを越える位置の文字抽出


/* SUBSTR */
data test;
    length x $3. y1 y2 $10.;
    x = "abc";
    y1 = substr( x, 1, 5 );
    y2 = substr( x, 5, 1 );
run;






/* SUBSTRN */
data test2;
    length x $3. y1 y2 $10.;
    x = "abc";
    y1 = substrn( x, 1, 5 );
    y2 = substrn( x, 5, 1 );
run;




上の例では、変数Xのlengthが「3」なのに対して、「substr(x,1,5)」や「substr(x,5,1)」みたいにlengthを飛び越える位置の文字を抽出しようとしています。


「SUBSTR」も「SUBSTRN」も結果は一緒ですが、
  • 「SUBSTR」はログに「NOTE: 関数SUBSTR(行 xx カラム x)の第x引数は無効です。」と出ます。
  • 「SUBSTRN」はこのNOTEメッセージが出ません。




4. 抽出開始位置に0以下を指定した場合


/* SUBSTR */
data test3;
    length x $3. y $10.;
    x = "abc";
    y = substr( x, -1, 4 );
run;






/* SUBSTRN */
data test4;
    length x $3. y $10.;
    x = "abc";
    y = substrn( x, -1, 4 );
run;




上の例では、「substr(x,-1,4)」というように抽出を開始する位置にマイナスの値を指定しています。

  • 「SUBSTR」はマイナスの位置を認識できず、ログに「NOTE: 関数SUBSTR(行 xx カラム x)の第2引数は無効です。」と出て第2引数が無効となり、結果は欠損値になります。
  • 「SUBSTRN」は以下のようにマイナス方向の位置も認識できるようです。


「-1」の位置から「4バイト」を抽出するんで「ab」が返されるわけですね。





5. 抽出する長さに0以下を指定した場合


/* SUBSTR */
data test5;
    length x $3. y $10.;
    x = "abc";
    y = substr( x, 1, -1 );
run;






/* SUBSTRN */
data test6;
    length x $3. y $10.;
    x = "abc";
    y = substrn( x, 1, -1 );
run;



上の例では、「substr(x,1,-1)」というように抽出する長さにマイナスの値を指定しています。

  • 「SUBSTR」はマイナスの長さを認識できず、ログに「NOTE: 関数SUBSTR(行 xx カラム x)の第3引数は無効です。」と出て第3引数が無効となり、結果は第2引数に指定した抽出開始位置から文字の終わりまでが抽出されます。
  • 「SUBSTRN」もマイナスの長さを認識できず、こちらはログのNOTEメッセージは出ないものの、結果は欠損値になります。



以上、5つに分けて比較してみましたが、特に1~3は覚えとくと便利です。4~5は細かい話なんで余裕あったら覚えとけばいいと思います。



2015年10月19日月曜日

最初の1バイト目だけ大文字に変換する


たとえば「abc def」→「Abc def」のような変換です。


前提条件
・ 最初の1バイト目はアルファベットである事。
・ 対象変数は半角の英数記号のみである事。


サンプルデータ

data DT1;
   length VAL $20.;
   VAL="proc print"; output;
   VAL="data step"; output;
run;

 VAL  
  proc print  
  data step



先頭の1バイト目だけ大文字にする

data DT2;
   length VAL2 VAL3 $20.;
   set DT1;

   * ① SUBSTR関数を使う ;
   VAL2 = upcase(first(VAL)) || substr(VAL,2);

   * ② 正規表現を使う ;
   VAL3 = prxchange('s/(^[a-z])/\U$1/', 1, VAL);
run;

 VAL2  
 VAL3  
 VAL  
 Proc print Proc print  proc print 
 Data step  Data step  data step

① SUBSTR関数を使う方法
FIRST関数は1バイト目を抜き出す関数
つまり1バイト目を抜き出して大文字にしたものと、2バイト目以降の文字を結合しています。

② 正規表現を使う方法
PRXCHANGE関数で正規表現による置換をしてます。
「prxchange('s/(^[a-z])/\U$1/', 1, VAL)」

「(^[a-z])」は先頭の文字がa~zのいずれかである場合、、という意味。
「\U$1」は上記を大文字に変換しています。


2014年8月20日水曜日

VERIFY(KVERIFY)関数の紹介




あまり日の目をみることがない「VERIFY関数」にスポットライトを当ててみたいと思います。



VERIFY関数

 VERIFY( 変数, "検索文字" )

  • 変数に対して、検索文字を含まない最初の位置(何バイト目か)を取得する。
  • 日本語などのマルチバイト文字には未対応です。


例
*** サンプルデータ ;
data DT1;
   length V1 $10.;
   V1 = "000A"; output;
   V1 = "00AB"; output;
   V1 = "ABCD"; output;
   V1 = "A000"; output;
run;

*** VERIFY関数を使う ;
data DT2;
   set DT1;
   V2 = verify( V1, "ABC" );
run;

 V1  V2  
  000A    1 
  00AB   1 
  ABCD    4 
  A000   2 

ここではV1に、「A」「B」「C」の文字を含まない最初の位置を返しています。
検索文字は「ABC」という文字を検索するのではなく、「A」「B」「C」と1バイトずつ検索していることに注意しましょう。



実践例

では、実際にVERIFYがよく使われるシチュエーション。
サンプルデータに対して、先頭の0を取った値が欲しいとします。

 V1  V2  
  000A   A  
  00AB  AB 
  ABCD   ABCD 
  A000  A000 


これを実現するには、正規表現を使うか、VERIFY関数がスマートなプログラムになるかなと思います。

data DT3;
  set DT1;

  length V2 V3 $10.;

  * 正規表現を使う例 ;
  V2 = prxchange("s/0*(.*)/$1/", 1, V1);

  * VERIFY関数を使う例 ;
  _VER = verify(V1, "0");
  if  _VER >=1  then V3 = substr(V1, _VER);
run;


簡単な説明となりますが、

正規表現の例では、PRXCHANGEという正規表現を使って置換処理をする関数で、先頭の0を抜いた文字に置き換えてます。

VERIFYを使う例では、まず0以外の文字が最初に出現する位置を取得して、SUBSTR関数でその位置からの文字を抜き出しています。



KVERIVY関数

こちらは日本語などのマルチバイト文字に対応しています。

 KVERIFY( 変数, "検索文字" )

  • 変数に対して、検索文字を含まない最初の位置(何文字目か)を取得する。
  • VERIFY関数が「何バイト目か」を取得するのに対し、KVERIFY関数は「何文字目か」を取得する事に注意。

例
*** サンプルデータ ;
data DT3;
   length V1 $20.;
   V1 = "あいうえお"; output;
   V1 = "あおいえい"; output;
run;

*** KVERIFY関数を使う ;
data DT4;
   set DT3;
   V2 = kverify( V1, "あお" );
run;

 V1  V2  
  あいうえお    2 
  あおいえい   3

V1に、「あ」「お」の文字を含まない最初の位置を返しています。
検索文字は「あお」という文字を検索するのではなく、「あ」「お」と1文字ずつ検索していることに注意しましょう。



わたし自身、VERIFY関数の面白い使い方をまだ探し中なので、こんな使い方できるよっていうのがあれば、教えてほしいです。


2013年11月8日金曜日

SUBSTR関数の小技




以下のデータセットがあったとして、、

data DT1;
    length VAR1 $20.;
    VAR1="abcde";
run;

変数「VAR1」の2~3バイト目を「XX」に置換したいとする。
だしたい結果は「aXXde」



「translate」とか「tranwrd」を思い浮かべるけど、以下みたいにも書ける。

data DT2;
    set DT1;
    substr(VAR1,2,2)="XX";
run;


substr関数の意外に知られてない書き方だと思う。ただし、

  • 2バイトを3バイトの文字に置換、みたいな異なる長さへの置換は出来ない。
    • 失敗例1: substr(VAR1,2,2)="XXX" → "aXXde"
    • 失敗例2: substr(VAR1,2,2)="X" → "aX de"
  • シングルバイト専用の関数のため、日本語などのマルチバイトは未対応。
  • 変数を上書きする(今回の例ではVAR1の変数値を置換した結果がVAR1に格納される)のでご注意下さい。