DOS コマンド版 get-url を使ってみる。

 昨日紹介した 拙作 DOS コマンド版 get-url を newLISP で使ってみます。
 Wikipedia から今日の記念日・年中行事を取り出して見ましょう。
 先ずはスクリプトから、

(define (whatstoday (day (1 2 (now ((now) -2)))))
  (letn (str (apply append (exec (string "get-url http://ja.wikipedia.org/wiki/"
                              (day 0)
                              "%E6%9C%88"
                              (day 1)
                              "%E6%97%A5" " UTF8 "
                              (if utf8 "UTF8" "")
                              )))
         pos (find {id=".E8.A8.98.E5.BF.B5.E6.97.A5.E3.83.BB.E5.B9.B4.E4.B8.AD.E8.A1.8C.E4.BA.8B">} str)
         pos (find "" str 1 pos)
         pos (+ pos 5)
         kday (0 (find "<h" (pos str)) (pos str))
         kparse (xml-parse kday (+ 1 2 4 8))
         res '())
        (dolist (li-pos (ref-all 'li kparse))
          (setf (li-pos -1) (+ $it 1))
          (let (tmp "")
            (dolist (x (ref-all "TEXT" (kparse li-pos)))
              (setf (x -1) (+ $it 1))
              (push ((kparse li-pos) x) tmp -1))
              (unless (null? tmp)
                (push tmp res -1))))
        res))

 UTF8 版 newLISP での動作は、

> (whatstoday)
("防災とボランティアの日(日本)1995年に発生した阪神・淡路大震災(兵庫県南部地震)では、国や地方自治体の危機管理体制の不備をはじめとするさまざまな問題が浮き彫りにされた一方で、ボランティア活動が活発化し「ボランティア元年」とも言われた。俳句の世界では季語「阪神忌」が存在する。" 
 "おむすびの日(日本)JA等でつくる「ごはんを食べよう国民運動推進協議会」が2000年11月に制定。阪神大震災ではボランティアの炊き出しで被災者が励まされたことから。" 
 "ひょうご安全の日(日本兵庫県)兵庫県が2006年に制定。" "尾崎紅葉祭(日本静岡県熱海市)尾崎紅葉の『金色夜叉』の中で、この日に熱海の海岸で主人公の貫一が恋人のお宮と別れる記述があることから。")
> 

 こんな感じ(1月17日)。
 ansi 版 newLISP なら

> (whatstoday '(1 18))
("\131^\131C\137\164\141\145\140R\130\204\147\250\129i\131^\131C\129j" "\147s\131o\131X\130\204\147\250\129i\147\250\150{\129j1924\148N1\140\14218\147\250\130\201\147\140\139\158\142s\137c\143\230\141\135\131o\131X\130\170\137c\139\198\130\240\138J\142n\130\181\130\189\130\177\130\198\130\201\151R\151\136\130\181\129A\147\140\139\158\147s\140\240\146\202\139\199\130\170\144\167\146\232\129B" 
 "118\148\212\130\204\147\250\129i\147\250\150{\129j\139\217\139}\146\202\149\241\151p\147d\152b\148\212\141\134118\148\212\130\204\146m\150\188\147x\140\252\143\227\130\204\130\189\130\223\129A2011\148N1\140\14218\147\250\130\230\130\232\138C\143\227\149\219\136\192\146\161\130\170\144\167\146\232\129B")
> 

 以上、如何でしょうか?

広告

newLISP マニュアル v.10.7.1 日本語訳公開

 ほぼ1年ぶりの安定版リリース。
 新規関数として、history が追加されています。

 ということで、newLISP の User Manual and Reference の全訳のリリースです。

newlisp_manual-10701
こちらからダウンロードしてください。

 目次も含め日本語併記にしてあります。
 Lutz氏のご好意によりこちらから見ることもできます。

 いつものように、間違いやおかしな点が有りましたら、こちらの blog までご一報ください。

 以上、如何でしょうか?

command-event で load を楽に

 以前、newLISP 組込関数の構文オンライン表示で使った command-event
 今回は、これを使って、ファイル名だけで lsp ファイルをロードします。

(command-event (fn (s)
  (let (x (read-expr s))
    (let (f (string x))
      (when (and (starts-with f "'") (ends-with f ".lsp"))
        (print "load ")
        (if (file? (1 f)) (load (1 f)) (println (1 f) "\nERR: no file")))))))

 末尾が “.lsp” の時、その lsp ファイルをロードします。
 ただし、ファイル名の先頭には、クォート(’)をつけます。
 使い方は、

C:\Language\newlisp>newlisp -n
newLISP v.10.7.0 32-bit on Windows IPv4/6 UTF-8 libffi, options: newlisp -h

>
(command-event (fn (s)
  (let (x (read-expr s))
    (let (f (string x))
      (when (and (starts-with f "'") (ends-with f ".lsp"))
        (print "load ")
        (if (file? (1 f)) (load (1 f)) (println (1 f) "\nERR: no file")))))))

$command-event
> $command-event
(lambda (s)
 (let (x (read-expr s))
  (let (f (string x))
   (when (and (starts-with f "'") (ends-with f ".lsp"))
    (print "load ")
    (if (file? (1 f))
     (load (1 f))
     (println (1 f) "\nERR: no file"))))))
> jdate
nil
> jdate.lsp
nil
> jdate
nil
> 'jdate.lsp
load jdate.lsp
> jdate
jdate
> (jdate)
"2016/9/28 20:59:45 水"
>

 こんな感じ。もちろん、フルパスも使えます。
 
 jdate については、こちらでどうぞ。
 
 以上、如何でしょうか?

projecteuler30

 projecteuler問題30は、自然数の各桁の 5 乗の和が、その自然数になるものを求め、その和を取るという問題。
 だから(汗)、スクリプトは力技で、

(define (pf i)
  (* i i i i i))
(let (lst)
  (for (i 2 999999)
   (if (= i (apply + (map pf (map int (explode (string i))))))
     (push i lst -1))
   )
  (println lst)
  (apply + lst)
)

 こんな感じ。
 これを実行すると

(4150 4151 54748 92727 93084 194979)
443839
> 

 と、自然数のリストとその和が出てきます。
 つまり、答えは 443839 。

 以上、如何でしょうか?

日付関数の日本語化、解説編...または、2038年問題対応?

 今回実装した関数 jdate, jdate:list, jdate:parse, jdate:value, jdate:now の内、list, parse, now は newLISP 組込関数と名前が同じです。通常、組込関数名は変数名にも関数名にも使えませんが、コンテキスト内でコンテキスト名を先付けして

jdate:list, jdate:parse, jdate:now

 とすれば、定義できます。
 また、これらを定義した場合、同名の newLISP 組込関数の呼び出しには、

MAIN:list, MAIN:parse, MAIN:now

 と書く必要もあります。
 それさえ気を付ければ、使いたい変数名や関数名が newLISP 組込関数名と同じだと嘆く必要はありません。まあ、そんなことは、無いでしょうけど(笑)
 この点が今回実装のポイントの一つです。
 さて、日付間の日本語化、前にも実装したことがあります。
 今回、敢えて実装したのは、前述のようにコンテキストにまとめたかったのと、2038年問題にも対応しておこうと思ったからです。
 newLISP は標準ライブラリを使って、あらゆるプラットフォームでの互換性を維持しています。そのため、日付に関する経過秒数を表現する型 time_t は、符号つき 32 ビットで 2038年1月19日3時14分7秒 までしか表現できません。これは、 64 ビット版 newLISP でも同じで、互換性維持のためだと思いますが、敢えて符号つき 32 ビットを使っています。
 だから、これは仕様です。まあ、あと20年はありますから、それまでに解決されるでしょうけど、、、
 それでも、20年くらい先はまだ生きていると思うので、その頃の予定を立てることがあるかもしれません。だから、取り敢えず、符号なし 32 ビット (2106年2月7日6時28分15秒相当)で実装してみました。本来なら、64 ビットで定義すべきですが、2100 年以降の予定なんて考えないから、これで十分かと(笑)
 calcDateValue と gmtime が、そのための関数です。
 一応、

> (jdate:value 2038 1 8)
2146489200
> (jdate:value 2106 2 6)
4294825200
> (jdate:parse "2106.2.6 6:28" "%Y.%m.%d %H:%M")
4294848480
> (jdate:list (jdate:parse "2106.2.6 6:28" "%Y.%m.%d %H:%M"))
(2106 2 6 6 28 0 37 6)
> 

 こんな感じで、使えます。

 以上、如何でしょうか?

追記:
 V10.7.0 の windoows 版で now を実行すると

> (now)
(2016 3 16 8 54 40 297940 76 3 600 -60)
> 

 このように、タイムゾーンのオフセット(分単位)が 600 となります。
 日本では 540 のはずなので、V10.7.0 の windoows 版のバグです。
 この点については Lutz氏 もわかっていて、次回、訂正されるそうです。
 それまで、ご注意を。

日付関数の日本語化

 newLISP の日付関数には、date, date-list, date-parse, date-value, now 等がありますが、date 以外はグリニッジ標準時なので、日本時間で使うには補正が必要です。
 また、date

> (date)
"Tue Mar 15 16:00:19 2016"
> 

 こんな風に、英語表記です。
 そこで、日本語表記、日本時間用の日付関数を定義してみました。

(context 'MAIN:jdate)
(setq YEAR0 1900 EPOCH_YR 1970 SECS_DAY (* 24 60 60))
(define (calcDateValue year month day (hour 0) (int-min 0) (sec 0))
; Algorithm quoting from newLISP source.
  (let (dateValue)
    (setq dateValue (+ (* 367 year) (- (/ (* 7 (+ year (/ (+ month 9) 12))) 4)) (/ (* 275 month) 9) day 1721013))
    (setq dateValue (+ (* dateValue 24 3600) (* hour 3600) (* int-min 60) sec -413319296)) 
    (setq dateValue (& dateValue 0xFFFFFFFF))
    (if (>= dateValue 4107596400) (-- dateValue 86400) dateValue)))
(define (leap (y ((now) 0)))
  (if (and (zero? (% y 4))
       (or (zero? (% y 400))
           (not (zero? (% y 100))))) 1 0))
(define (yearsize year) (+ (leap year) 365))
(define _ytab '((31 28 31 30 31 30 31 31 30 31 30 31)(31 29 31 30 31 30 31 31 30 31 30 31)))
(define (gmtime tm)
; Algorithm quoting from common C-library source.
  (letn (year EPOCH_YR
         dayclock (% tm SECS_DAY)
         dayno (/ tm SECS_DAY)
         tm_sec (% dayclock 60)
         tm_min (/ (% dayclock 3600) 60)
         tm_hour (/ dayclock 3600)
         tm_wday (% (+ 4 dayno) 7))
    (while (>= dayno (yearsize year)) 
      (-- dayno (yearsize year))
      (++ year))
    (let (tm_year (- year 0); YEAR0
          tm_yday dayno
          tm_mon 0
          tm_mday 1)
       (while (>= dayno (_ytab (leap year) tm_mon))
         (-- dayno (_ytab (leap year) tm_mon))
         (++ tm_mon))
       (++ tm_mday dayno)
       (list tm_year (++ tm_mon) tm_mday tm_hour tm_min tm_sec (++ tm_yday) tm_wday))))
(define (jdate:now (offset 540) idx)
  (if idx (MAIN:now offset idx) (MAIN:now offset)))
(define (jdate:value)
  (if (args) (- (apply calcDateValue (args)) (* 9 60 60))
    (date-value)))
(define (jdate:list (sec (jdate:value)) idx)
  (letn (offset (* 9 60 60)
         lst (gmtime (+ sec offset)))
    (if idx (idx lst) lst)))
(define (jdate:jdate (value (jdate:value)))
  (let (lst (jdate:list value)
        str (if utf8 '(227 128 63 230 156 136 231 129 171 230 176 180 230 156 168 233 135 145 229 156 159 
 230 151 165)
                     '(129 64 140 142 137 206 144 133 150 216 139 224 147 121 147 250)))
    (append (join (map string (0 3 lst)) "/") " "
            (join (map string (3 3 lst)) ":") " "
            (if utf8 ((* 3 (lst 7)) 3 (pack (dup "b" (length str)) str))
                     ((* 2 (lst 7)) 2 (pack (dup "b" (length str)) str))))))
(define (jdate:parse dateStr formatStr , res)
  (if (= formatStr "%c") (setq formatStr "%m/%d/%y %H:%M:%S"))
  (let (specs (find-all "(%.)" formatStr)
        regStr (replace "(%.)" (replace "." formatStr "\\.") "(.+)" 0)
        months '("" "Jan" "Feb" "Mar" "May" "Jun" "Jul" "Aug" "Sep" "Oct" "Nov" "Dec")
        Months '("" "January" "February" "March" "April" "May" "June" 
                 "July" "August" "September" "October" "November" "December")
        dateLst '(1900 1 1 0 0 0))
    (setq res (regex regStr dateStr))
    (when res 
       (setq res (rest (filter string? res)))
       (when (= (length specs) (length res))
          (dolist (i (transpose (MAIN:list specs res)))
             (case (i 0) 
               ("%b" (setf (dateLst 1) (find (i 1) months 1)))
               ("%B" (setf (dateLst 1) (find (i 1) Months 1)))
               ("%d" (setf (dateLst 2) (int (i 1) 0 10)))
               ("%H" (setf (dateLst 3) (int (i 1) 0 10)))
               ("%m" (setf (dateLst 1) (int (i 1) 0 10)))
               ("%M" (setf (dateLst 4) (int (i 1) 0 10)))
               ("%S" (setf (dateLst 5) (int (i 1) 0 10)))
               ("%Y" (setf (dateLst 0) (int (i 1) 0 10)))
               ("%y" (setf (dateLst 0) (int (string "20" (i 1)))))
               (true )))))
  (if-not (find nil dateLst) (apply jdate:value dateLst))))
(context MAIN)

 使える関数は、jdate, jdate:list, jdate:parse, jdate:value, jdate:now で、それぞれ date, date-list, date-parse, date-value, now に対応します。
 使い方は、

> (jdate)
"2016/3/16 17:8:15 火"
> (jdate:list)
(2016 3 16 17 8 23 75 2)
> (jdate:value 2016 3 16)
1458054000
> (jdate:now)
(2016 3 15 17 8 48 630885 75 2 600 -60)
> (jdate:parse "2010.10.18 7:00" "%Y.%m.%d %H:%M")
1287352800
> (jdate:list (jdate:parse "2010.10.18 7:00" "%Y.%m.%d %H:%M"))
(2010 10 18 7 0 0 291 1)
> 

 こんな感じ、解説は次回に、、、

newLISP マニュアル v.10.7.0 日本語訳公開

 久々の安定版リリース。
 新規関数として、統計でよく使われる二乗和関数 ssq が追加されています。
 また、Windows 用に 64ビット版が用意されています。それに伴い、組込定数 ostype が Windows版では “Windows”になります。ご注意を。

 ということで、newLISP の User Manual and ReferenceGUI functionsCode Patterns の全訳のリリースです。

newlisp_manual-10700
guiserver_manual-171
CodePatterns-10700
こちらからダウンロードしてください。

 目次も含め日本語併記にしてあります。
 Lutz氏のご好意によりこちらから見ることもできます。

 いつものように、間違いやおかしな点が有りましたら、こちらの blog までご一報ください。

 以上、如何でしょうか?

projecteuler29

 projecteuler問題29は、2 から 100 までの自然数を 2 乗から 100乗 して、同じものを除くと何個になるかという問題。
 だから、スクリプトは単純、

(let (lst)
  (for (i 2 100)
    (for (j 2 100)
      (push (apply * (cons 1L (dup i j))) lst -1)
    )
  )
 (length (unique lst)))

 こんな感じ。1L を cons しているのは、大整数にするため。100 乗するには 64 ビット整数では足りないですからね(笑)

(let (lst)
  (for (i 2 100)
    (for (j 2 100)
      (push (apply * (map bigint (dup i j))) lst -1)
    )
  )
 (length (unique lst)))

でも同じになります。
 ここで bigint は整数を大整数に変換します。
 また、unique は同一数値を除去してくれます。
 これを実行すると

9183
> 

 と答えが求まります。

 以上、如何でしょうか?

projecteuler28

 projecteuler問題28は、自然数をらせん状に並べ、角の数値のみを足した和を求めるもの。といっても、一辺が 1001 になるまでですが(笑)
 スクリプトは単純、

(let (i 1 j 2 lst '(1))
  (while (< j 1001)
    (dotimes (k 4) (++ i j) (push i lst -1))
    (++ j 2))
   (println lst)
   (apply + lst)
   )

 こんな感じ。一週ごとに求める自然数の間隔が2つずつ増えていくのがミソ。
 これを実行すると

(1 3 5 7 9 13 17 21 25 31 37 43 49 57 65 73 81 91 101 111 121 133 145 157 169 183 
 :
 986049 987043 988037 989031 990025 991021 992017 993013 994009 995007 996005 997003 
 998001 999001 1000001 1001001 1002001)
669171001
> 

 答え 669171001 が求まります。

 以上、如何でしょうか?

projecteuler27

projecteuler27

 projecteuler問題27は、二次方程式

n^2 + an + b, where |a| < 1000 and |b| < 1000

において、n = 0 から素数が続く数が最大となる係数を探し出し、その積を求めるもの。
 何も考えずに力ずくで求めるスクリプトは、

(define (func n a b)
  (+ b (* a n) (* n n)))
(setq lst '() len 1)
(for (i -999 999)
  (for (j -999 999)
    (let (k 0 res '() flag true)
       (while flag
         (let (ans (func k i j))
            (if(and (> ans 0) (= 1 (length (factor ans)))) (push (list k i j) res -1)
                (setq flag nil)))
           (++ k))
    (when (> (length res) len) (setq len (length res)) (push res lst -1)))))
(lst -1 -1)
(apply * (1 (lst -1 -1)))

 これを実行すると

(lambda (n a b) (+ b (* a n) (* n n)))
1
nil
(70 -61 971)
-59231
> 

 こんな感じで答え -59231 が求まります。
 この時の二次方程式は

n^2 - 61n + 971

 で n = 0 ~ 70 で 71 個の素数が作られます。
 実際に計算してみると、

> (map (hayashi func -61 971) (sequence 0 70))
(971 911 853 797 743 691 641 593 547 503 461 421 383 347 313 281 251 223 197 173 
 151 131 113 97 83 71 61 53 47 43 41 41 43 47 53 61 71 83 97 113 131 151 173 197 
 223 251 281 313 347 383 421 461 503 547 593 641 691 743 797 853 911 971 1033 1097 
 1163 1231 1301 1373 1447 1523 1601)
> 

 こんな感じ。
 ここで関数 hayashi は拙作で、(newlisp-utility.lsp にあります)

(hayashi func -61 971)

 は以下の式等価です。

(fn (x) (func x -61 971))

 以上、如何でしょうか?