#MatchRep41.mscr ver.2008.1.11######################### #文字列マッチ/置換をregexp感覚で行うライブラリMortScript #for MortScript 4.1 Public Release # #by モバイル板MortScriptスレの1 #ref. to http://pc11.2ch.net/test/read.cgi/mobile/1172140262/l50 # #【更新】 # MortScript 4.1の新機能を使って高速化しました。 # #<使い方> # # CallScriptFunction( "\fullpath\to\MatchRep41.mscr", 出力用変数, マッチ検索対象文字列, マッチパターン ) # マッチパターンの書式: s/hoge/voge/gi" # # ※「m」の場合は、(修飾子がgの場合でも)最初にマッチしたindexが数値で出力されます。 # ※「s」の場合は、置換後の文字列が出力されます。 # マッチしなかった場合は、入力文字列がそのまま出力されます。 # #<例> # # inStr = "Fool gooner hoops." # pat = "s/foo|goo|hoo/bar/gi" # # CallScriptFunction( "\fullpath\to\MatchRep41.mscr", outStr , inStr, pat ) # # → outStr : "barl barner barps." # #<出来ること&出来ないこと> # # "m/hoge|moge|ko\|ge/gi" # "s/hoge|moge|ko\|ge/voge/gi" # # ・デリミタはどんな英数字記号でも指定出来ます。が、これ↓は出来ません。 # # ×  m{hoge}i # # ・ "|" (pipe. "OR")が使えます。 # ・ マッチ文字列中の "|" は "\" でエスケイプ出来ます。 # ・ デリミタとして使用されている文字記号は、マッチ文字列中 "\" でエスケイプ出来ません。 # ・"g"(グローバルマッチ)と"i"(ケースインセンシティヴ)が使えます。 # # ・メタ文字は使えません。 # ・"( )" も使えません。 # #・HTMLタグ等、半角括弧に囲まれた部分 # および"&"と";" に囲まれた部分(ASCII文字コード)をマッチ検索/置換できます。 # "s/<.*>|[.*]|(.*)|{.*}|&.*;/hoge/g" # などと記述して下さい。とはいえ、".*" はメタ文字ではありません。単なる“書式”です。 # # # # ############################################### #メイン Local() In = argv[1] Pat = argv[2] #Message( In & ", " & Pat ) error_title = "MatchRep Error" #エラー処理 If( In eq "") Call( "error_proc", 2, error_title ) EndIf If( Pat eq "") Call( "error_proc", 3, error_title ) EndIf #オペレータとデリミタの検出 op = SubStr( Pat, 1, 1 ) del = SubStr( Pat, 2, 1 ) #Message( op & ", " & del ) #シンタックスの検証 If( op eq "m" || op eq "s" ) Split( Pat, del, 0, pat_array ) #mの場合 If( op eq "m" ) If( Not IsEmpty( pat_array[4] )) Call( "error_proc", 1, error_title ) #OKならば Else Or_In = pat_array[2] modfr = pat_array[3] #"|" 処理 CallFunction( "Or", Or_Out_array, Or_In, modfr ) #パターンマッチ検索 idx = 0 ForEach matstr in array ( Or_Out_array ) CallFunction( "match", idx_temp, In, matstr, modfr ) If( idx ) If( idx_temp > 0 && idx > idx_temp) idx = idx_temp EndIf Else idx = idx_temp EndIf EndForEach Out = idx EndIf #sの場合 Else If( Not IsEmpty( pat_array[5] ) ) Call( "error_proc", 1, error_title ) #OKならば Else Or_In = pat_array[2] repstr = pat_array[3] modfr = pat_array[4] #"|" 処理 CallFunction( "Or", Or_Out_array, Or_In, modfr ) #もしグローバル置換でない場合、複数マッチ候補の中で最も先頭にマッチするものを #いったん探してから置換 If( Find( modfr, "g" ) = 0 ) idx = 0 ForEach matstr in array ( Or_Out_array ) CallFunction( "match", idx_temp, In, matstr, modfr ) If( idx ) If( idx_temp > 0 && idx > idx_temp) idx = idx_temp earlst_matstr = matstr EndIf Else idx = idx_temp earlst_matstr = matstr EndIf EndForEach If ( idx ) # Message( In & ", " & earlst_matstr ) CallFunction( "replace_ng", Out, In, idx, earlst_matstr, repstr ) Else Out = In EndIf #グローバル置換の場合は、全部置き換える。 Else ForEach matstr in array ( Or_Out_array ) CallFunction( "replace_g", Out, In, matstr, repstr, modfr ) In = Out EndForEach EndIf EndIf EndIf Return( Out ) #オペレータが間違っている場合 Else Call( "error_proc", 1, error_title ) EndIf #以下、サブルーチン ########################## #マッチサブルーチン #CallFunction( "match", idx, In, matstr, modfr ) Sub match #Message( In ) Local() In = argv[1] matstr = argv[2] modfr = argv[3] If ( matstr eq "<.*>" || matstr eq "[.*]" || matstr eq "(.*)" || matstr eq "{.*}" || matstr eq "&.*;" ) par_op = SubStr( matstr, 1, 1 ) par_cl = SubStr( matstr, Length( matstr ), 1 ) If ( Find( In, par_op ) > 0 && Find( In, par_op ) < Find( In, par_cl )) idx = Find( In, par_op ) Else idx = 0 EndIf ElseIf( matstr ne "" ) #ケース処理 If( Find( modfr, "i" )) idx = Find( ToLower( In ), ToLower( matstr )) Else idx = Find( In, matstr ) EndIf EndIf # Message( idx ) Return( idx ) EndSub ############################# #置換サブルーチン(not global) #CallFunction( "replace_ng", Out, In, idx, matstr, repstr ) Sub replace_ng #Message( In ) Local() In = argv[1] idx = argv[2] matstr = argv[3] repstr = argv[4] #Message( In & ", "& idx & ", "& matstr & ", "& repstr) #マッチ文字列を置換文字列に置換 ##SubStr()では、文字列長を"0"とした場合、空文字列ではなく、 ##開始インデックス以降のすべての文字列を返すので If( idx = 1 ) preStr = "" Else preStr = SubStr( In, 1, idx - 1) EndIf If ( matstr eq "<.*>" || matstr eq "[.*]" || matstr eq "(.*)" || matstr eq "{.*}" || matstr eq "&.*;" ) par_op = SubStr( matstr, 1, 1 ) par_cl = SubStr( matstr, Length( matstr ), 1 ) postStr = SubStr( In, Find( In, par_cl, idx ) + 1 ) Else postStr = SubStr( In, idx + Length( matstr )) EndIf Return( preStr & repstr & postStr ) EndSub ############################# #置換サブルーチン(global) #CallFunction( "replace_g", Out, In, matstr, repstr, modfr ) Sub replace_g Local() In = argv[1] matstr = argv[2] repstr = argv[3] modfr = argv[4] #Message( In & ", "& matstr & ", " & repstr & ", " & modfr) #括弧除去の場合 If ( matstr eq "<.*>" || matstr eq "[.*]" || matstr eq "(.*)" || matstr eq "{.*}" || matstr eq "&.*;" ) par_op = SubStr( matstr, 1, 1 ) par_cl = SubStr( matstr, Length( matstr ), 1 ) str = "" first = 1 ForEach var in split ( In, par_op, 0 ) # Message( var ) If ( first ) str = var first = 0 Else If( Find( var, par_cl )) str = str & repstr & SubStr( var, Find( var, par_cl ) + 1 ) EndIf EndIf EndForEach Out = str Else If( Find( modfr, "i" )) str = "" first = 1 m_idx = 0 ForEach var in split( ToLower( In ), ToLower( matstr ) , 0) If ( first ) If( Length( var )) str = SubStr( In, 1, Length( var )) EndIf first = 0 Else str = str & repstr & SubStr( In, m_idx, Length( var )) EndIf m_idx = Length( str ) + Length( matstr ) + 1 EndForEach Out = str Else Out = Replace( In, matstr, repstr ) EndIf EndIf Return( Out ) EndSub #################### #"|"処理サブルーチン #CallFunction( "Or", Or_Out_array, pat_array[2], pat_array[3]) Sub Or Local() Or_In = argv[1] modfr = argv[2] #変数の初期化 esc = 0 i = 1 #パターンマッチ文字列を頭から一文字ずつ検証 ForEach l in charsOf ( Or_In ) #もし直前で"\"によってエスケイプされていない場合 If( esc = 0 ) Switch( 1 ) #文字がもし"\"ならば、次の文字をエスケイプ Case( l eq "\" ) Or_In_var esc = 1 #文字がもし"|"ならば、次の文字からは次の候補文字列 Case( l eq "|" ) i = i + 1 esc = 0 #いずれでもなければ、文字を候補arrayのi番目として文字列の末尾に追記 Case( l ne "\" && l ne "|" ) Or_Out_array[i] = Or_Out_array[i] & l esc = 0 EndSwitch #もし直前で"\"によってエスケイプされている場合 Else #文字をそのまま現在の候補文字列の末尾に追記 Or_Out_array[i] = Or_Out_array[i] & l esc = 0 EndIf EndForEach Return( Or_Out_array ) EndSub ########################### #エラーメッセージ表示&スクリプト終了サブルーチン Sub error_proc Local() error = argv[1] error_title = argv[2] Switch( error ) Case( 1 ) Message( "Syntax Error!", error_title ) Case( 2 ) Message( "Input string is empty.", error_title ) Case( 3 ) Message( "Match pattern is empty.", error_title ) EndSwitch Exit EndSub