hinekure.net が http://hspdev-wiki.net/ から自動クローリングした結果を表示しています。画像やリソースなどのリンクが切れています。予めご了承ください。
String/置換 - HSP開発wiki
トップ    編集凍結 差分バックアップ添付複製名前変更リロード   新規一覧単語検索最終更新   最終更新のRSS

文字列の置換

考え方はこんな感じです。あとは実装するだけ。

「対象文字列 < 置換文字列」の置換

サンプルとなる文字列sを"aaaBBaaBBaBBBBaaa"、対象となる文字列tを"BB"、置換する文字列rを"XYZ"とする。

サンプル文字列sの先頭から末尾に向かって順次、対象文字列tを検索し、置換する位置を求める。

位置01234567891011121314151617
tBB
saaaBBaaBBaBBBBaaa

マッチしないので検索を進める。
   は検索開始インデックス。

位置01234567891011121314151617
tBB
saaaBBaaBBaBBBBaaa

マッチしないので検索を進める。

位置01234567891011121314151617
tBB
saaaB
X
B
Y
a
Z
aBBaBBBBaaa

インデックス3でマッチしたのでこの位置に"XYZ"を置き換えればいいのだが・・・
このまま置き換えてしまうとインデックス5の"a"が潰れてしまう。
よって「対象文字列 < 置換文字列」の場合は作業バッファが必要となる。
   はマッチした文字列の先頭インデックス。

位置01234567891011121314151617
tBB
saaaBBaaBBaBBBBaaa
bufaaaXYZ

作業バッファbufを用意して置換を行う。

  1. 検索開始インデックスからマッチした位置までの文字列をバッファにコピーする。
        はコピーした文字列。
  2. その後ろに置換文字列をくっつける。
        は連結した置換文字列。
位置01234567891011121314151617
tBB
saaaBBaaBBaBBBBaaa
bufaaaXYZ
検索を再開する。
マッチしないので検索を進める。
   は検索開始位置。
   は前回マッチした位置。
位置01234567891011121314151617
tBB
saaaBBaaBBaBBBBaaa
bufaaaXYZaaXYZ

インデックス7でマッチしたので置換を行う。
   は新たにマッチした位置。

  1. 検索開始インデックスからマッチした位置までの文字列をバッファにコピーする。
        はコピーした文字列。
  2. その後ろに置換文字列をくっつける。
        は連結した置換文字列。
    以下同様に検索をし、マッチしたら置換を繰り返す。
位置01234567891011121314151617
tBB
saaaBBaaBBaBBBBaaa
bufaaaXYZaaXYZaXYZ
位置01234567891011121314151617
tBB
saaaBBaaBBaBBBBaaa
bufaaaXYZaaXYZaXYZXYZ
位置01234567891011121314151617
tBB
saaaBBaaBBaBBBBaaa
bufaaaXYZaaXYZaXYZXYZ
これ以上検索しても見つからないとき、最後の検索開始位置から終端までの文字列をコピーする。
がこの作業バッファbuf、現時点で確保した領域をフルにつかってこれ以上連結できません。
(都合上、表に合わせただけなんです。)
(自動確保が効けば問題なしです。)
よって「対象文字列 < 置換文字列」の場合、作業バッファは前もって大きめに確保しておかなければならない。
(大きめ、かつ最低限必要なサイズを求めることもできます。)
位置0123456789101112131415161718192021
tBB
saaaBBaaBBaBBBBaaa
bufaaaXYZaaXYZaXYZXYZaaa
これで全て置換し終えました。

「対象文字列 = 置換文字列」の置換

「対象文字列 > 置換文字列」の置換

作業バッファを使わずスライド法でやってみます。

スライド法というのは自分が勝手につけた名前で一般的ではないです。 -- kz3

Splitを利用した置換アルファ版(HSP3.2以降)

上と同様にサンプルとなる文字列を"aaaBBaaBBaBBBBaaa"、対象となる文字列を"BB"、置換する文字列を"XYZ"とする。

まず、"BB"を区切りとして"aaaBBaaBBaBBBBaaa"をSplitにかけると"aaa"、"aa"、"a"、"(空白)"、"aaa"に分割される。
そして分割した文字列同士の間に"XYZ"を入れれば繋げれば簡単に文字列を置換できる。

Splitを利用した置換のサンプル
sreplace.hsp

Everything is expanded.Everything is shortened.
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
-
|
|
|
|
|
|
!
 
 
 
 
 
 
 
 
#module "srep_module"
#deffunc sreplace var out,str base,str rbase,str rout
/*
文字列の置換
書式:sreplace 変数,文字列1,文字列2,文字列3
 
パラメータ
変数:結果を代入する変数
文字列1:元の文字列
文字列2:対象文字列
文字列3:置換文字列
 
置換した回数をstatに返します。
*/
    sdim srep_array,512,1;作業用変数swp_arrayの初期化
    srep_str==base;作業用変数srep_strにbaseを代入
    split srep_str,rbase,srep_array;元の文字列を対象文字列を区切りとして分割
    if length(srep_array)>=2{
        ;分割した文字列同士の間に置換文字列を入れる
        srep_str==srep_array(0)
        repeat length(srep_array)-1,1
            srep_str==srep_str+rout+srep_array(cnt)
        loop
        out == srep_str
    }
return length(srep_array)-1
#global
 
;テスト
    a=="aaaBBaaBBaBBBBaaa"
    sreplace b,a,"BB","XYZ"
    mes b
    mes ""+stat+"回置換しました"

コメント

  • 自動確保が効くといっても頻繁に自動確保するケースが出てくると、自動確保のための時間が指数的に溜まってくるので、速度重視の場合はやっぱり最初に領域をがぼっと確保したほうがいいと思います。が果たしてこの言い分は本当なのだろうか。 -- kz3 2005-10-18 22:09:12 (火)
  • いろいろと大量の置換対象からのみなるテキスト(64byte*16*16 = 256Kbyte)でテストしてみたけど、検索する対象の文字列が多くなればなるだけ時間はかかりますね。あと演算子による連結はヌル文字を検索するという処理も含まれているからだと思う。連結位置を自己管理してmemcpyでメモリ間コピーすればちょっと早くなるかも? -- kz3 2005-10-18 22:15:29 (火)
  • もしくはpokeでメモリ間コピー。 -- kz3 2005-10-18 22:16:27 (火)
  • 正確なベンチマーク速度は測っていませんが、段違いに速くなりました。自分でも驚きです。載せたいけどサイズ大きいんですよねぇ・・・^^; -- kz3 2005-10-18 22:23:44 (火)
    • これが例のブツです。プリプロセッサでスイッチします。実際のコードは下のほうです。汗。 -- kz3 2005-10-18 22:43:27 (火)
    • 例のブツにループ中の検索位置のカウンタ表示を追加しました。+=演算子による置換の際、カウンタが進むにつれ遅くなっていることが分かると思います。 -- kz3 2005-10-19 09:56:06 (水)
  • あ〜!GENKIさん、『置換さん』というのを作っていたんですね! -- kz3 2005-10-19 13:19:51 (水)
  • ぐふふ(怪)さっそくreplace.txtのHotSoupProcessor?をHSPに置換しよう! -- kz3 2005-10-19 13:23:28 (水)
  • ・・・。強制終了・・・。きっとクリップボードのデータが大き過ぎたんだな;; -- kz3 2005-10-19 13:24:39 (水)
  • ・・・。ルーターのADSLランプが異常点滅し、全く回復の兆しがみえないのでchkdskをかけたら直った・・・みたいです。(A゚ー゚; -- kz3 2005-10-19 14:00:29 (水)
  • やはり純粋にアドレス(のオフセット)とコピーサイズを直に指定するmemsetが3つの中で高速な印象です。
    pokeの場合コピー元に指定した文字列変数のサイズを調べてからメモリ間コピーしますがループ中で呼ぶと何度もコピー元の文字列サイズを計算する(計算するのに対象の文字列の先頭からヌル文字までを検索します。)からmemcpyより遅くなるのだと思う。
    memcpyは事前に一回計算するだけでループ中では一発で位置を指定しているから無駄がないということかな? -- kz3 2005-10-19 14:10:39 (水)
  • kz3さんのアルゴリズムをまねて、自前で作ったスクリプトが動きません。 ハハハ  -- hiroki? 2005-10-20 11:15:43 (木)
  • 見せてくださ〜い!☆_☆ -- kz3 2005-10-20 11:21:23 (木)
  • 送り方どうやるの? -- hiroki? 2005-10-20 11:30:49 (木)
  • 上メニューに[添付]というのがあるのでそこから添付フォームを設定してファイルをアップロードできますよ〜。 -- kz3 2005-10-20 11:34:15 (木)
  • 上メニュー以外に下メニューアイコンの、「クリップ付き」アイコンが[添付]と同じです^^ -- kz3 2005-10-20 11:35:06 (木)
  • どうしてもオーバーフローになっちまう -- hiroki? 2005-10-20 11:37:17 (木)
  • 確認中〜^^ -- kz3 2005-10-20 11:40:19 (木)
  • なんか・・・while-wendのマクロ展開がおかしい??? -- kz3 2005-10-20 11:54:20 (木)
  • 分かった。40行目の次回の検索開始位置 index1+=moji2 これが間違っている。moji2じゃなくてmoji2の文字サイズですね〜 -- kz3 2005-10-20 11:59:51 (木)
  • ....は..恥ずかしい。  でもindex1+=moji2su に直してもオーバーフロー -- hiroki? 2005-10-20 12:04:13 (木)
  • : moji2su=strlen(moji2)と入れると動くけど変な結果だから、調べてみます -- hiroki? 2005-10-20 12:06:47 (木)
  • 分かった。index1とmutchを比較する意味がない。mutchはオフセットだが、index1はmoji1中の検索開始位置、およびpeekの読取位置ですね〜。 -- kz3 2005-10-20 12:09:56 (木)
  • でもpeekしたついでにindex1+ ってしてるんだけど...。 -- hiroki? 2005-10-20 12:20:53 (木)
  • index1は置換が進むにつれて増えていきますよね?でもmutchは検索開始位置から見つかった位置までのオフセットなので場合によっては、
    index1 : mutch = 130 : 5
    ということもあってこの場合、while index1 < mutchはループに入る前に偽りなので・・・ -- kz3 2005-10-20 12:25:31 (木)
  • index1からのスタートなのでmutchがindex1より小さいことはありえないんだけど。 -- hiroki? 2005-10-20 12:29:54 (木)
  • 偽りなので・・・検索開始から見つかった位置までの置換対象外の文字列がコピーされず、置換文字列だけを repeat moji3su ループで連結しているのでXYZXYZ...となる。 -- kz3 2005-10-20 12:31:36 (木)
  • ありえますよ〜〜〜〜!!おおいにありえます;;(どんなサンプル書こうかな) -- kz3 2005-10-20 12:32:56 (木)
  • 例えばこんな感じ。
      1
      2
      3
      4
      5
      6
      7
      8
      9
     10
     11
    
     
     
     
     
     
     
     
     
     
     
     
    
    s = "abcdefghijklmn"
     
    mutch = instr(s, index1, "e")
    mes "index1 : mutch = " + index1 + " : " + mutch
    mes strmid(s, index1, mutch)
     
    index1 += mutch+1
     
    mutch = instr(s, index1, "g")
    mes "index1 : mutch = " + index1 + " : " + mutch
    mes strmid(s, index1, mutch)
    • kz3 2005-10-20 12:37:41 (木)
  • みんな最初は間違えるinstr。検索文字中の探した文字列の「絶対位置」ではなくて、検索開始位置からどれだけ離れた位置に見つかったという「オフセット値」なんです。 -- kz3 2005-10-20 12:40:47 (木)
  • 初めてスタート位置からの文字数だとわかりました。 repeat mutch に変えると動きました。 ごめんなさい。 添付します。 -- hiroki? 2005-10-20 12:46:58 (木)
  • いやーー プログラミングって奥が深いしたのしいですね。 -- hiroki? 2005-10-20 12:50:02 (木)
  • やったねb^−^ -- kz3 2005-10-20 12:51:37 (木)
  • 更新ってどうするんですか -- hiroki? 2005-10-20 12:52:08 (木)
  • 同一ファイルの添付は元を削除しないといけないので、下にある添付ファイルリストの対象ファイルの[詳細]をクリック後に削除を選択できます^^ -- kz3 2005-10-20 12:55:10 (木)
  • できました。 あーーー疲れた。 -- hiroki? 2005-10-20 13:00:40 (木)
  • お疲れ様です・・・では恒例(?)「hsp3」64*16*16*16byte->「HotSoupProcessor3」置換速度テスト。爆。 -- kz3 2005-10-20 13:09:49 (木)
  • 0で除算したって怒られた。 すいません出かけます 結果は後ほど -- hiroki? 2005-10-20 13:26:35 (木)
  • 急いでいたので、変数直してなかった。 うまくいきました。 添付します。 では。 -- hiroki? 2005-10-20 13:36:31 (木)
  • v3try_strreplace1b.hspにベンチマークテストのためのタイマー表示を追加しました。こちらをどうぞ。旧バージョンはサイズが大きい(これもだけど)ので削除しました・・・。&ref(): File not found: "v3try_strreplace2b.hsp" at page "String/置換"; -- kz3 2005-10-20 14:07:46 (木)
  • テスト中にマウス移動とか他アプリの処理によって時間は変わってきます。pokeの方がmemcpyより早いという場合もありました^^; -- kz3 2005-10-20 14:09:28 (木)
  • なんかpeek-pokeの方が早いんですけど!!!´ロ` -- kz3 2005-10-20 14:13:04 (木)
  • (いやいやそんなバカな・・・ワナワナ)微妙に早かったり遅かったり。orz
    インデックス動かすのに+=で加算するよりインクリメントの方が早いということかな・・・ワナワナ
    結構文字列置換というベターな話題でも盛り上がりますね^^;(僕だけか) -- kz3 2005-10-20 14:23:28 (木)
  • でも、いろんなアルゴリズムがありますよね。 僕なんか速度より簡単な方法を取ってしまいます。 -- hiroki? 2005-10-20 16:30:42 (木)
  • 基本はどれも『追いかけっこ』ですね^^ -- kz3 2005-10-20 17:16:00 (木)
  • 勝手に追加してしまいましたが構いませんよね? 最近追加されたSplitを使った置換、書いておきます。 アルファ版って書いてあるのは中身じゃなくて説明の方です。 -- Alkw_lzy 2010-05-13 (木) 03:05:45

URL B I U SIZE Black Maroon Green Olive Navy Purple Teal Gray Silver Red Lime Yellow Blue Fuchsia Aqua White

トップ    編集凍結 差分バックアップ添付複製名前変更リロード   新規一覧単語検索最終更新   最終更新のRSS
Last-modified: 2010-05-13 (木) 03:05:45 (1305d)