検索と置換

1996.11.16


 AppleScriptで文字列を扱う場合、検索と置換に関してはデリミタ(テキスト項目区切り)を使用することで高速に実行できます。

 普通にスクリプトを組むと、検索と置換いうのは「全体の文字列を1文字目から1文字ずつずらして読み込んでいき、検索文字列と一致した部分を置換文字列と置き換えていく」という風になると思うのですが、これでは処理に時間がかかり過ぎてしまいます。何せ10KBの文章を検索&置換しようと思えば、1バイト文字で10,000回以上の処理が必要になってしまうわけですから。

 そこで、「デリミタ (テキスト項目区切り)」の登場となります。デリミタは「ある文字列をリストに切り分けるための目印」のようなものと考えて下さい。以下に例を示します。

 アップルスクリプトのテキスト項目区切りを“:”にする
 “aaa:bbb:ccc”のすべてのテキスト項目
  --- 結果:{"aaa","bbb","ccc"}

 set AppleScript's text item delimiters to ":"
 text items of Str
  --- result : {"aaa","bbb","ccc"}


 逆も考えられます。

 アップルスクリプトのテキスト項目区切りを“**”にする
 文字列としての{"aaa","bbb","ccc"}
  --- 結果:“aaa**bbb*ccc”

 set AppleScript's text item delimiters to "**"
 {"aaa","bbb","ccc"} as string
  --- result : "aaa**bbb**ccc"


 この「アップルスクリプトのテキスト項目区切り(AppleScript's text item delimiters)」というちょっとながったらしい言葉が「AppleScriptで使用されるデリミタ」です。これには好きな文字列を必要なときに設定できます。つまり、デリミタ“:”の状態である文字列をリストに分解しておき、その文字列を今度はデリミタ“**”の状態で文字列に戻せば、もとの文字列に含まれていた“:”はすべて“**”に置換されるわけです。

 例えばStrを目的の文字列とすると、

 アップルスクリプトのテキスト項目区切りを“:”にする
 StrをStrのすべてのテキスト項目にする
 アップルスクリプトのテキスト項目区切りを“**”にする
 Strを文字列としてのStrにする

 set AppleScript's text item delimiters to ":"
 set Str to text items of Str
 set AppleScript's text item delimiters to "**"
 set Str to Str as string

 とするだけで、Strに含まれる“:”はすべて“**”に置換されます。簡単でしょ?

 ここでちょっと注意しなければならないことがあります。それは、この「デリミタ」がスクリプト全体で共通して使用されるものだということです。(グローバル変数的、と表現できます)

 例えばあるサブルーチンでデリミタを“---”にして文字列の処理をしている最中に、FindAndReplaceというサブルーチンをさらに呼んだとしましょう。このFindAndReplaceの中でもしデリミタを“+++”に変更したとすると、もとのルーチンに復帰してからもデリミタは“+++”のままになってしまいます。これが原因のエラーに、私(Karino)も最初泣かされました。

 これを防ぐ方法としては、サブルーチンを開始するときにその時点のデリミタを変数に取り込んでおき、終了するときにもとのデリミタに戻すような操作をしてやるといいでしょう。

 次のサブルーチンは検索&置換のためのもので、十分実用に耐えます。

FindAndReplace(targetStr,pre,pro)とは
  CurDelimをアップルスクリプトのテキスト項目区切りにする
  アップルスクリプトのテキスト項目区切りをpreにする
  targetStrをtargetStrのすべてのテキスト項目にする
  アップルスクリプトのテキスト項目区切りをproにする
  targetStrを文字列としてのtargetStrにする
  アップルスクリプトのテキスト項目区切りをCurDelimにする
  targetStrを返す
以上

on FindAndReplace(targetStr, pre, pro)
  set CurDelim to AppleScript's text item delimiters
  set AppleScript's text item delimiters to pre
  set targetStr to text items of targetStr
  set AppleScript's text item delimiters to pro
  set targetStr to targetStr as string
  set AppleScript's text item delimiters to CurDelim
  return targetStr
end FindAndReplace


 また、純粋な「検索」(指定の文字列が何文字目から始まるか)ということも、この方法を用いれば簡単に得ることができます。(このサブルーチンはエラー処理をしていません)

Find(targetStr,findStr)とは
  CurDelimをアップルスクリプトのテキスト項目区切りにする
  アップルスクリプトのテキスト項目区切りをfindStrにする
  targetStrをtargetStrのすべてのテキスト項目にする
  NumListを{}にする
  CurNumを0にする
  findNumを(findStrの文字を数える)にする
  iをtargetStrのおのおのにして
    CurNumをCurNum+((文字列としてのi)の文字を数える)+1にする
    NumListをNumList&CurNumにする
    CurNumをCurNum+findNum−1にする
  以上
  アップルスクリプトのテキスト項目区切りをCurDelimにする
  NumListの項目1から-2までを返す
以上

on Find(targetStr, findStr)
  set CurDelim to AppleScript's text item delimiters
  set AppleScript's text item delimiters to findStr
  set targetStr to text items of targetStr
  set NumList to {}
  set CurNum to 0
  set findNum to count character of findStr
  repeat with i in targetStr
    set CurNum to CurNum + (count character of (i as string)) + 1
    set NumList to NumList & CurNum
    set CurNum to CurNum + findNum - 1
  end repeat
  set AppleScript's text item delimiters to CurDelim
  return items 1 thru -2 of NumList
end Find

 以上、デリミタを利用した検索&置換の方法でした。


Tipsに戻る
AppleScriptのページに戻る
このホームページに関するお問い合わせは、karino@drycarbon.comまで。