みんなに優しく、解りやすくをモットーに開設しています。 以下のルールを守りみんなで助け合いましょう。
1.ファイルメーカーで解らない事があればここで質問して下さい。 何方でも、ご質問・ご回答お願いします。 (優しく回答しましょう)
You are not logged in.
いつもお世話になっております。
環境はMac FM17 です。
タイトルの通り、全ての文字の間にスペースを挿入する計算式を模索しております。
例として、
「name」フィールドの内容が"やまだたろう"であった場合、
「name_space」に
"や ま だ た ろ う" もしくは
" や ま だ た ろ う "
と帰ってくる「name_space」の計算式(計算式自動入力or計算フィールド)が目標です。
補足として、
・「name」の内容は1文字〜上限なし
・「name」と「name_space」フィールドは同じテーブル
・挿入されるテキストは最終的にSubtituteでスペースに変換するので指定はありません
これまではスクリプトにおいてloop処理で1文字ずつスペース挿入していく方法をとっていたのですが、
フィールドの計算式自動入力で一発で求められないかと思い、ご教示賜わりに参りました。
よろしくお願いいたします。
Offline
While (
[
text = self ;
i = length ( text )
] ;
i > 1 ;
[
text = Replace ( text ; i , 0 ; " " ) ;
i = i - 1
] ;
text
)
を、自動計算に設定します。
手打ちなので打ち間違いがあるかも。
Last edited by Shin (2022-07-27 10:01:27)
Offline
Shin 様
早速のご回答ありがとうございます。
While関数を使用すればご教示いただいた内容で結果を求められるのですね。
ただ、While関数はFM18が始点のようでFM17では使用することができませんでした。。
Offline
ですよね。
同じ考えで
Let
Evaluate
を使った再起式でできますが、
繰り返しフィールドに一文字ずつブランクを付けて展開すれば
簡単では。
印刷のフォーマットの問題でしょうか?
とすれば、他の方法も考えられますが。。
Offline
チポ様
ありがとうございます。
おっしゃるとおり印刷のフォーマットに起因するものです。
イメージですが表彰状のようなレイアウトで下記のようになることが最終目標です。
"○ ○ 月 ○ ○ 日 、" & name_space & "殿 は 素 晴 ら し い 成 績 を お さ め ま し た 。"
name_space = "や ま だ た ろ う"
恥ずかしながらカスタム関数がないかと淡い期待をしておりました。
Last edited by noel (2022-07-27 10:35:20)
Offline
久しぶりに再起式を書いてみました。
Let ([
$_str = Self
;~count = Length ( $_str )
;$_n = ~count+1
;$_f = "Case ( $_n ≤ 1; $_str ;
LET([$_str=Replace ( $_str ; $_n ; 0 ; Char ( 32 ) ); $_n=$_n-1] ; Evaluate($_f))
)"
];
Evaluate($_f)
)
Offline
qb_dp様
ありがとうございます。
そっくりそのまま使用させていただき、求めていた結果がでるようになりました。
まだ式内で何が行われているか理解できておりませんが、
一つずつ噛み砕きながら身につけるようにいたします。
Shin様、チポ様、qb_dp様
こんなに早くレスポンスをいただき感謝の念でいっぱいです。
改めてありがとうございました!!
Offline
繰り返しフィールドに1文字ずつ入れておいて、配置する方法も簡単ですよ。
Offline
作文用紙のように繰り返しフィールドを1マス1マスとして使っていくということでしょうか。
確かに簡単ですし、おもしろく、メンテナンス性も良さそうですね。
次回同じようなレイアウトを作成する際は試してみます。
ありがとうございます!
Offline
>「name」の内容は1文字〜上限なし
となってますが、このタイプの再帰式は300文字ぐらいが限界なので、念のため。(400文字で結果が?になることだけ確認済)
himadanee様
限界があるのですね!
頭に入れておくようにいたします。
ご注意いただきありがとうございます。
Offline
あんまりテストしてないけど、ようやくできた...
これも限界はあるだろうけどとりあえず6400文字まではエラーにならないのを確認しました。(2^300文字ぐらいまでいけるのかな?)
(文字の間に、なので末尾にはスペースが付きません)
Let ([
$str = text
;$f = "Let ( [ $s=$str ; n = Length($s) ] ;
Case ( n ≤ 1; $s ;
Let([
l=Left($s;Ceiling(n/2))
;r=Right($s;Floor(n/2))];
Evaluate(Substitute ( $f ; \"$\"&\"str\" ; Quote(l) ) ) & Char(32) & Evaluate(Substitute ( $f ; \"$\"&\"str\" ; Quote(r) ) ) ) ) )"
];
Evaluate($f)
)
脇からの余計な質問をさせてください。
この問題をテキストの文字数を106496とし、下記のスクリプトでloopで処理したとところ処理時間が再帰式やWhile関数(上限をLength ( テスト)+1に設定)に比べ3倍近く掛かりました(loop:86689,while:27282,再帰式:27702)。
変数を設定 [ $count; 値:2 ]
変数を設定 [ $text; 値:recursive::a1 ]
Loop
Exit Loop If [ $count-1 ≥ Length ( $text ) ]
変数を設定 [ $text; 値:Replace ($text ;$count; 0 ; " " ) ]
変数を設定 [ $count; 値:$count + 2 ]
End Loop
フィールド設定 [ recursive::b1; $text ]
今までloop方が速いとの思い込みがあるので私の書いたスクリプトに問題が在るのではないかと思い投稿させていただきました。
ご教授お願いいたします。
環境は、Windows10 FM19.5.2
スクリプトは、一種のインタープリターですので、実行するごとに1行ずつコンパイルされて実行されます。ですから、回す回数にもよるでしょうが、loop は遅くなりますよ。
スクリプトの実行は、行数に比例して時間がかかります。上のスクリプトでしたら、実行時には30万ステップ以上になりますので、それを考えれば、その程度の時間差は出ると思います。
変数を設定 [ $count; 値:2 ]
変数を設定 [ $text; 値:recursive::a1 ]
Loop
Exit Loop If [ [ Let ( [ $text = Replace ($text ;$count; 0 ; " " ) ; $count = $count + 2 ] ; $count-1 ≥ Length ( $text ) )] ]
End Loop
フィールド設定 [ recursive::b1; $text ]
にしてみると、ステップ数が半分程度になるので、早くなるかも。
変数を設定 [ $text; 値:recursive::a1 ]
変数を設定 [ $count; 値:Length ( $text ) ]
Loop
Exit Loop If [ [ Let ( [ $text = Replace ($text ;$count; 0 ; " " ) ; $count = $count - 1 ] ; $count ≤1 )] ]
End Loop
フィールド設定 [ recursive::b1; $text ]
にすると、計算量が少しだけ減るので、少し早くなるかも。
Last edited by Shin (2022-07-31 08:30:10)
Offline
shin様 有り難うございます。早速 「Let ( [ text =・・」を「 Let ( [ $text =・・」に直し処理してみたところ
前のバージョン:83979
後のバージョン:処理実行されず
の結果となりました。
スクリプトの実行は、行数に比例して時間がかかります。上のスクリプトでしたら、実行時には30万ステップ以上になりますので、それを考えれば、その程度の時間差は出ると思います。
単に私の知識不足で勝手に思い込んでいただけだけなのですね。
あれ?FM17だと無条件でAdvancedじゃなかったですか?
カスタム関数でも再帰ができます。
例えばinspaceという関数を定義する。
Case ( Length ( text ) < 2 ; text ;
Left ( text ; 1 ) & " " & inspace ( Right ( text ; Length ( text ) - 1 ) )
)
これだと5万文字が上限かな?再帰呼び出しの回数が変更できるのはいつからだったかな?
こちらの検証では動いていますが。
だいたいの想定通りに、実行時間は2/3になっています。
下のアルゴリズムにすると、2/3になりました。思ったより早くなりました。Length() が遅いのかな。
Offline
shin様 失礼しました。スクリプトの設定順を最初のまま使用していたので、正しいloop処理が行われていませんでした。申し訳ありません。
当方の計測結果は:30220
となりました。再帰式やWhile関数での処理時間に劣るもののすごい数値です。私には単純なアルゴリズムしか思いつきませんがこんなに違うとは!!
有り難うございました。
「後のバージョン」が実行されなかったのは、一か所$が抜けてたんでしょう。
再帰回数の指定ができるのは18.0からだった。
https://help.claris.com/ja/pro-help/con … rsion.html
どうでもいい実験結果の報告です。
1000000文字のテキストで試してみました。
再帰式:275932ms
while:3152270ms
loop:途中で止めました。
212992では
loop:121819ms
再帰式:61318ms
while:114066ms
サンプル数が少ないのとPCのスペックの問題もあり参考まで。
計算式のサイズ: テキスト、数値、参照するフィールド、演算子、およびカッコを含め最大 30,000 文字
のはずですが???
Offline
計算フィールドではなくフィールド設定の方の計算式で実行しています。結果はLength ( フィールド)で1999999文字が返されているので問題はないかと思いますが?
3万文字の制限は計算式を設定するダイアログの制限だったと思ってたんですが、今データビューアで試してみたら、
Evaluate(
Substitute ( 10^100-1 ; 9 ; Substitute ( 10^100-1 ; 9 ; "+1" ) )
)
は計算できました(+1を1万回なので2万文字)
が、どっちかを^200にしたら(4万文字)エラー(結果が?)になってしまいました。(FM19.5.2.201)
#12の私の再帰式は、文字列を半分にしてそれぞれ計算式に埋め込んで再帰呼び出ししている(変数のバッティングを避けるため)ので、Evaluateに与える文字列が3万文字を超えてるはずなんですが、不思議ですね。
こっちでやっても確かに102400文字でもエラーなく計算終了してました。(計算フィールド)
同じ文字数でも演算子の数とかも関係してるのかな?
そうでした。^200にする代わりに"+100"にしてみたらエラーにならなかった。う~ん。ややこしい。
ベンチマークはやってみてないですが、WhileがEvaluateの再帰式より遅いというのはちょっとがっかりな感じですね。さすがにこんなに長いテキストを扱うことはほとんどないと思いますけど...
アルゴリズム自体が再考の余地あり?
以前は、その制限で再帰式は数千再帰くらいが限度でしたよね。計算途中の制限が無くなったのでしょうかね。
Offline
私は、再帰式につては門外漢なのですが昔以前あったの同名のサイトで文字列をバイト数で抜き出す方法を教わった際、最初に後ろから削る再帰式(再帰回数が298~302回限度)を教わりさらに別の方から次の改良版なら制限がないと教わったような記憶が・・・かなり曖昧な・・
Let([
$byt=1000000; //制限バイト数を指定
$txt=Left ( recursive::a1; $byt ); //文字列フィールドを指定
$LengthB="Length($txt & Filter($txt;RomanZenkaku(KanaZenkaku($txt))))";
$LeftB="Case(Evaluate($LengthB)<=$byt; $txt; Let([$txt=Left($txt; Length($txt)-1)];Evaluate($LeftB)))"
];
Evaluate($LeftB)
)
今回テキストが百万文字を超えたためこれを使い百万文字に文字数を整えました。(当然時間が多少掛かりました)
[ Generated in 0.006 seconds, 7 queries executed - Memory usage: 574.92 KiB (Peak: 611.83 KiB) ]