このページは福井県立大学の田中求之が2006年1月まで運用していた Mac のサーバ運用に関する会議室 「Web Scripter's Meeting」の記録です。情報が古くなっている可能性がありますのでご注意ください。

ListToLinesの仕様(一次元配列の変換)について

発言者:山本 武
( Date Thursday, April 23, 1998 13:10:44 )


ListToLines の仕様について
 Tanaka's OSAXにはお世話になっているのですが、その中で ListToLines の
仕様について確認したいのです。

● ListToLines {"abc", "xxx"} itemDelimiter tab lineDelimiter return
--->>>一次元のリストをListToLinesした場合の出力なのですが
"abc
xxx"
と二行になりますが、 直感的には "abc xxx"と一行になってほしい気持ちもあります。
 (逆のitemsToListでは、"abc xxx"→ {"abc", "xxx"}となります)

 一行にするためには
ListToLines {{"abc", "xxx"}} itemDelimiter tab lineDelimiter return
とすればよいのは分っているのですが、”本当は”{"abc", "xxx"}なのか、 {{"abc", "xxx"}}なのか
を確認していただけたらと思って投稿しました。

 背景は、Jeditの中でhtmlのテーブル作成ツールを作っていたのですが、
一行きりのデータを変換する場合にうまくいかず、結局この仕様を把握していないことが
原因だとわかりました。

 申し訳ありませんが、御確認お願いできないでしょうか。
 山本 武

田中求之 さんからのコメント
( Thursday, April 23, 1998 15:15:37 )

ListToLines (MT Join List) は、リストの各アイテムを行とする文字列を吐き出す
というものですので、{"abc","xxx"} は2行の文字列になります、これが仕様です。

タブ区切りの1行にしたい場合には、山本さんのおっしゃるように {{"aaa","xxx"}} 
にする必要があります。

その意味では、itemsToList (linesToList ではない点に注意)(MT Parse) と
linesToList とは対称にはなっていません。


山本 武 さんからのコメント
( Thursday, April 23, 1998 15:51:48 )

 コメント有難うございます。
 class of item 1 of aLIst...等を使って文字列か、配列かを判断して
 {}を噛ませるように改造したいと思います。

田中求之 さんからのコメント
( Thursday, April 23, 1998 16:22:35 )

"aaa    xxx" が {{"aaa","xxx"}} に変換されるように 2.0 の MT Parse では
変更します。

itemsToList は、もともとは行には対応していなかったのを拡張したという
経緯がありますので、過去との互換性のために、1行だけの文字列の場合に
限って "aaa   xxxx" が {"aaa","xxx"} になるようにしていたのですが、
2.0 では、この特別扱いをなくします。

あと、型変換に関してまたバグが見つかってますので (^_^; 、それも修正しておきます。
また、as パラメーターの名前を、コンフリクトを避けるために retutn as に変更
します。

このように、問題点などは今後はすべて 2.0 での修正を行いますので、できれば 2.0b
を使ってください。

山本 武 さんからのコメント
( Thursday, April 23, 1998 22:52:52 )

 時代は2.0のようですね。確かにMT Parseでは余計な場合分けが不要ですね。

今、Tanaka'sOSAX1.xの簡単な使い方を紹介したドキュメントを書き進めていて
10項目(自分がよく使うものに限定していますが)くらいまできたのですが
この際、2.0向けに書いてしまおうと思います。
 今後ともサポートお願いします。

(できれば10進→16進、16進→10進なんて関数があればなぁ...なんて
Tanaka'sOSAXとは馴染まないですね。独り言です)では

→  Tanaka's OSAX1.x紹介等のページ

山本 武 さんからのコメント
( Thursday, April 23, 1998 22:54:54 )

URL間違えました。

→   Tanaka's OSAX1.x紹介等のページ(正しい)

田中求之 さんからのコメント
( Friday, April 24, 1998 04:11:27 )

>できれば10進→16進、16進→10進なんて関数があればなぁ

AppleScript で作ることは難しくないですけどね(ただし、速度は別にして)

山本 武 さんからのコメント
( Friday, April 24, 1998 08:30:29 )

 わざわざコメント有難うございます。

 AppleScriptのコマンドの組み合わせて16進→10進は一応出来たのですが
一回の変換にざっとですが僕の環境で10〜100(はいかないかな)m秒程度かかります。
変換の回数が10とか100ならばいいのですが、時には10000程度の変換をする必要が
あるのですが、そうなると一気に1分を超える処理になります。せめて10倍早くなれば
現実的な処理が可能だと思っています。夏のAllegroにも期待してます。

 現状はPerlを使って変換しているので、不便はないといえば無いのですが
”ちぇっ”とよく思うのです。どなたか16進変換のOSAXの情報があったら教えて下さい。
宜しくお願いします。

野本夏俊 さんからのコメント
( Friday, April 24, 1998 10:03:34 )

ぼくも欲しいです。
できればn進ヒN進ができるととても助かります。(2〜36進ぐらい)

田中求之 さんからのコメント
( Friday, April 24, 1998 19:37:31 )

確かにスクリプトでは遅いですね。先程、試しに

"ABCDEF0123456789"

という文字列を 16->10 進変換するのを 1000 回繰り返したら 140 秒ほど
かかってしまいました。

Scriptweb の osax のコーナーを見ても、それらしいものはありませんね。

osax だと、どの程度早くなるのかな…

田中求之 さんからのコメント
( Friday, April 24, 1998 21:54:15 )

>osax だと、どの程度早くなるのかな…

とりあえず、8文字までの Hex 文字列を整数に直す(8文字までの Hex 文字列を4バイト
の符号付き long integer の Hex とみなす)というのを作って "FEDCBA98" (=-19088744)
を 1000 回変換させてみたら、Quadra 840AV (私の手元にある最速マシン (^_^;; )で
11 秒でした。やっぱ osax 呼び出しのオーバーヘッドがけっこうあるなぁ、という感じです。

作っちゃったものは、そのうち登録します (^_^;

山本 武 さんからのコメント
( Friday, April 24, 1998 23:24:08 )

 わざわざスピードまで測っていただいて恐縮です。
僕はC言語の経験もあるし、16進→10進くらいはCで書くのは
そんなに大変ではないでしょう。本当は自分でOSAXくらい
作れればいいのでしょうが、Macintosh上のOSAX作りは
想像がつきません。

 「Cをそこそこ知っている人向けに一日の講習で15000円
くらいでOSAXの作り方伝授します」ってのがあったら喜んで
いくんだけどなぁ...できれば東京、できれば宇都宮で。

 でも、「自分の為に作る」と「皆が使える」の差は天と地ほど
違うだろうし。
 とりあえず、夏のAllegroに期待してみます。

野本夏俊 さんからのコメント
( Friday, April 24, 1998 23:24:51 )

HyperCardでは少し速いようですからosaxでも望みはあるのでは?
以下のスクリプトでAppleScript=35秒、HyperCard=7.5秒でした。

-------------AppleScript-------------------------------
set NumChars to "0123456789"
set NUM to "ABCDEF0123456789"

set S to current date
repeat 1000 times
 set ans to 0
 repeat with i in NUM
  if i is not in NumChars then set i to (ASCII number of i) - 55
  set ans to 16 * ans + i
 end repeat
end repeat
display dialog (((current date) - S) as text) & return & ans

-----------------HyperCard------------------------------
on mouseUp
 put "ABCDEF0123456789" into NUM
 
 put the ticks into S
 repeat 1000
  put 0 into ans
  repeat with i = 1 to number of chars of NUM
   put char i of NUM into aa
   if aa is not a number then put chartonum(aa)-55 into aa
   put 16*ans+aa into ans
  end repeat
 end repeat
 put ans && (the ticks - S)/60
end mouseUp

ただこれだとAppleScriptでは答えが1.23798137388771E+19
になってしまいます。もっといい方法はありませんか?

Hideaki Iimori さんからのコメント
( Saturday, April 25, 1998 00:06:42 )

PowerMac8100/80上ですが、
Usertalk (Frontier)だと 1000回繰り返しで1秒弱(1000 msec)

  local
    d
    s = "FEDCBA98"
  for i = 1 to 1000
    d = long("0x" + s)

Cだと 1000回繰り返しで 1.8 msec

long    htod(const char *s)
{
long    d = 0;
char    ch;

    while ((ch = *s++) != 0) {
        long    n;
        if (('0' <= ch) && (ch <= '9')) {
            n = ch - '0';
        }else if (('A' <= ch) && (ch <= 'F')) {
            n = ch - 'A' + 10;
        }else if (('a' <= ch) && (ch <= 'f')) {
            n = ch - 'a' + 10;
        }else{
            break;
        }
        d = (d << 4) + n;
    }

    return d;
}

void    main()
{
    const char  *s = "FEDCBA98";
    for ( long i = 0; i < 1000; i++ ) {
        long    d = htod(s);
    }
}

》やっぱ osax 呼び出しのオーバーヘッドがけっこうあるなぁ

こういった簡単な処理を OSAXにすると処理時間の 95%〜99.9%は呼
び出しのオーバーヘッドになってしまいますね。

田中求之 さんからのコメント
( Saturday, April 25, 1998 01:16:05 )

>ただこれだとAppleScriptでは答えが1.23798137388771E+19
>になってしまいます。

これは AppleScript の仕様です。

AppleScript の整数(integer)は、32 bit の符号付き整数( long といわれる
型)になっていますので、これを越えるものは、自動的に real に変換されます。

ただし、本来 long は 正負 2^31 つまり -2147483647 〜 2147483647 なんですが
AppleScript では 2^29 の範囲に限定されており、-536870911 〜 536870911
の範囲が整数となっています。これをこえると real に変換されて扱われます。
スクリプトエディタに 536870912 と書いて Syntax check すればわかりますよ

田中求之 さんからのコメント
( Saturday, April 25, 1998 01:21:57 )

>本当は自分でOSAXくらい
>作れればいいのでしょうが、Macintosh上のOSAX作りは
>想像がつきません。

入り口と出口の部分さえマスターすれば、あとはゴリゴリと処理を書いていくだけ
ですよ (^_^;;  もちろん Inside Macintosh は傍らに必要になりますが、
アプリケーションなどに較べると、限定されている分、作りやすいです。なんたって
HyperTalk でこうやって作っている人間がいるくらいですから (^_^;;

田中求之 さんからのコメント
( Saturday, April 25, 1998 01:25:54 )

さすがに Frontier には long() なんてのがちゃんとあるんですね。それに
早いなぁ。

>こういった簡単な処理を OSAXにすると処理時間の 95%〜99.9%は呼
>び出しのオーバーヘッドになってしまいますね。

ですねぇ。スクリプトよりは確実に早くなるんですけど、なんだか損をしたような気に
なりますね (^_^;; リストを受け取って、リストの各アイテムを一気に変換して
しまうことで呼び出し回数を減らして速度を稼ごうかしら、と姑息なことを考えてい
ます (^_^;;

田中求之 さんからのコメント
( Saturday, April 25, 1998 02:02:53 )

osax の作り方などに関しては、 MacTech マガジンのバックナンバーのスクリプト
関連の記事に目を通されるとよいと思います。

私は、以下のページに Additions という項目でのっている記事によって osax の
作り方を学びました(正確には、これの翻訳が『Macintosh プロフェッショナル
プログラミング』という本に載っていたのを読んで)。



→  Languages, Scripting (MacTech Artcle archive)

重松修 さんからのコメント
( Saturday, April 25, 1998 02:23:59 )

私も早速FBで試してみました。
まあ、沢山裏で走らせてのアバウトな状態で測定しましたが、Iimoriさんと
同じアルゴリズムで、100万回ループで

 PowerPC604e  11秒(1000回だと0.011秒)
 68040/25MHz 32秒(0.032秒)

という結果です。

実は、8100/80もあるけど、電源入れるの面倒くさい。(^^;;

FutureBASICはPowerPCネイティブではないですが、まあ、そこそこ頑張ってる
とおもいます。もっと頑張ってもっとスマートなアルゴリズムを採用すれば、
ほんの少しだけ高速になります。

BASICだけで、4割程度速度アップしましたので、アセンブラに書き換えれば、
6〜7割速度アップすると思います。でも、Cでかいたものの方がさすがに
ネイティブだから速いですね。。。

LOCAL FN htod(@strPtr&)
  adr& = strPtr&+PEEK(strPtr&)
  WHILE adr&>strPtr&
    c% = PEEK(adr&)
    SELECT
      CASE c%>=_"0" AND c%<=_"9"
        d& = (d&<<4)+(c%-48)
      CASE c%>=_"A" AND c%<=_"F" 
        d& = (d&<<4)+(c%-55)
      CASE c%>=_"a" AND c%<=_"f"
        d& = (d&<<4)+(c%-87)
      CASE ELSE
        d& =  d&<<4
    END SELECT
    DEC(adr&)
  WEND
END FN = d&

s& = FN TICKCOUNT
t$ = "FEDCBA98"
FOR i&=1 TO 1000000
  d& = FN htod(t$)
NEXT
PRINT ((FN TICKCOUNT-s&)/60!)

野本夏俊 さんからのコメント
( Monday, April 27, 1998 12:48:24 )

>AppleScript の整数(integer)は、32 bit の符号付き整数( long といわれる
>型)になっていますので、これを越えるものは、自動的に real に変換されます。

これは仕方がないことだと思っています。
数値として求めるならどうにもならないことですが、何とか文字列として求める
アルゴリズムがないもんでしょうか?

>リストを受け取って、リストの各アイテムを一気に変換してしまうことで呼び出し回数を
>減らして速度を稼ごうかしら、と姑息なことを考えています (^_^;;

これ、できれば、文字列を指定した長さで区切って変換してリストを返してくれたりすると
すんごく嬉しいんですが....
(たとえば"FF001293F1"を{255,0,18,147,241}と返してくれる)
あるいはitemsToListに指定バイト数で区切ったリストを返す様なオプション
("FF001293F1"を{"FF","00","12","93","F1"}と返してくれる)が
あってくれるといいな〜と思うんですが... ぼくだけかも知れないですけど....

田中求之 さんからのコメント
( Monday, April 27, 1998 14:38:34 )

> "FF001293F1"を{"FF","00","12","93","F1"}と返してくれる

これでしたら、以下のようなハンドラーを作っておいて呼べばよいと思います。

on splitStr(myData, x)
  
  set dx to (length of myData) div x
  set dy to (length of myData) mod x
  
  set myList to {}
  
  repeat with z from 1 to dx
    set end of myList to (text from character ((z - 1) * x + 1) to (z * x) of myData)
  end repeat
  
  if dy is not 0 then
    set end of myList to (text from character (dx * x + 1) to -1 of myData)
  end if
  
  return myList
  
end splitStr

splitStr("FF001293F1", 2) --> {"FF", "00", "12", "93", "F1"}

田中求之 さんからのコメント
( Tuesday, April 28, 1998 03:29:04 )

文字列のリストを渡して、各アイテムを Hex -> Dec の変換を行うようにしてみたら、
1000 個のリストでも2秒ほどで処理が済んでしまいます。やっぱ、osax 呼び出しの
オーバーヘッドはたいしたもんだ (^_^;

とりあえず、この Hex To Dec の osax は、明日、あ、もう今日か、の夕方にでも
登録します( Tanaka's osax にはまだ含めません)

野本夏俊 さんからのコメント
( Tuesday, April 28, 1998 10:03:27 )

ありがとうございますーーーーーーーー

田中求之 さんからのコメント
( Tuesday, April 28, 1998 12:17:33 )

Hex の文字列を10進数の整数(long)に変換する osax を登録しておきました。

リストを渡すと、各項目を hex の文字列と見なして、変換しようとします。
ただし、

・文字数が8文字を越えるもの( = 32bit Int を越えるもの)
・変換後の整数が、正負 2^29 (AS の Int)を越えるもの
・Hex 以外の文字が含まれているもの
・文字列ではない(文字列に変換できない)もの

については、そのまま何もしません

→  Hex osax

山本 武 さんからのコメント
( Monday, May 04, 1998 15:36:22 )

HEX TO DEC、有り難く使わせて頂きます。
久しぶりのアクセスになった関係で返事が送れました。
これでまた、AppleScriptの活用範囲が広がりました。
いつも本当に有難うございます。