ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

Lispで書くテキスト処理コミュの他コミュのネタ(^^;)

  • mixiチェック
  • このエントリーをはてなブックマークに追加
他所のコミュのネタをパクって、Emacs-Lisp書いてみようというトピックです。そこのコミュにコメントしても良いのですが・・・

コメント(17)

さっそくここのネタをパクってみます(笑)。
[sed/awk: ファイルの挿入]
http://mixi.jp/view_bbs.pl?id=4524444&comm_id=1615

一応、インクルードするファイルの中にまた#INCLUDEが見つかったら、再帰的に処理するようにしてあります。ただし、無限ループするようにファイルが指定されている場合はmax-lisp-eval-depthに引っ掛かって止まるようになっています(^^;)
http://nobulign.way-nifty.com/Lisp/WS000092.JPG

#それにしても日下部陽一さんがmixiに居たとは・・・ちょっとビックリ。
誰か、ここの課題をやってみませんか?(笑)
http://mixi.jp/view_bbs.pl?id=3203624&comm_id=836
作ってみました。Perlだと、ちょっとした処理でも長いプログラムになりがちなので、見通しが悪いですよね。

http://nobulign.way-nifty.com/Lisp/WS000099.JPG
Perlのコミュをのぞいていたら、Perlでmakeコマンドを作っちゃった・・・なんていうトピックスがありました。コードが公開されていたわけではないので、真偽のほどは分かりません。ということで、Lispでmakeコマンドを作ってみましょう!

・・・と言いたいところですが、これはちょっと重たいと思いますので、とりあえずMakefileを作るLispでも考えてみましょうか。実はむかし作ったことがあるのですが、コードは無くしてしまったし、もう一度最初から作っても大したことはないのでやってみましょう。

で、どんなMakefileを作るかもいっしょに考えてください。こういう場合はこれでMakefileが出来るというふうに書き込んでいただければ良いです。

最終的にEmacsをビルドするMakefileとか出来ると面白いかもしれませんね(笑)。

#単なるお遊びですので、その点お忘れなく。
何も書き込みがないのでちょっと時間稼ぎ(笑)。

たとえばLINUX上でCソースをコンパイルしてオブジェクトを作るだけであれば、Makefileなんて必要無くて、「FILE=`echo *.c` make ${FILE//.c/.o}」ってやれば、全部コンパイルしてくれる。ヘッダとの依存関係を気にするのであれば「FILE=`echo *.c` gcc -M ${FILE} | make -f - ${FILE//.c/.o}」ってやれば良い。

#ホントかな?(笑)
バッチモードでキーボードマクロを使ってMewでメールを飛ばそうとしたけど上
手くいかない・・・というトピがMewのコミュにあって、4ヶ月経っていますがフ
ォローがありません。私はMewのコミュには参加していないし、Mewは使っていな
いし、そもそもバッチモードの中でキーボードマクロを使う発想は持ちあわせて
いないのでどうしようもないのですが・・・。

最近はそういうのが流行っているのでしょうか??

「Emacs Lispでコードを書く場合は出来るだけコマンドを使わないようにしよう」
というルール?があったと思います。たとえばbeginning-of-bufferのHelpを見
ると「Don't use this command in Lisp programs!」と書かれていると思います。
代わりに(goto-char (point-min))を使いますね。next-lineやprevious-lineな
ども同様です。なので、私の中ではコード中にキーボードマクロを埋め込むこと
自体あり得ないのですが、そういうのをバッチで実行してしまおうという発想は
理解できません。

それに「Emacsはシングルスレッドなので、バッチモードでは非同期処理が出来
ず、適宜sit-forを呼んでやらないといけない」というようなこともどこかのペ
ージで読みました。

ただ・・・私が今の拙いコードを書けるようになるまでの過程で、たしかにキー
ボードマクロからプログラムを作れるのではないかと考えていたこともあります。
そして、そのレベルからdefunなになにといきなり関数を書けるようになるには、
かなり長い時間いろいろとイメージトレーニングしたり、Emacs上で試したりを
繰り返したと思います。そう考えると気持ち的にはすごくよく分かる気がしたの
でした。

さて、みなさんはどう考えるのでしょうね・・・。
こんにちは。少し話題が古いかもしれませんが、それはまさか、僕のスレッドでしょうかw。
http://mixi.jp/view_bbs.pl?id=51988870&comm_id=7536
このコミュニティに入ったばかりです。
そうですね、そのマクロを書いたのが去年頃で、lispの知識が全くないまま書いてしまったものです。実は、一回適当に"emacs lisp intro"ってinfoページを読みながら関数を書きましたが、これってマクロで書いた方がnoobフレンドリーってどっかの読んで、確かにマクロの方が短くて簡単でした。

まぁ、今になってはemacs lisp introのinfoページを読み終えて、emacs lisp reference manualを参考にしながらなんとかlispらしきコードが書けるようになってきています。
大学2年生のときからemacsを使い始めて(前はviを使っていたが、日本語でレポートを書かないといけないということで…emacsのlatexモードがとても助かりました)、いつの間にかカストマイズしすぎちゃって気づいたら端末と同じくずっと開いていることになっていた…。
現在大学4年生で、今年がlisp系の言語emacs lisp/scheme/logoがマイブームで^^。卒研のプログラムでもテキスト処理してくれるスクリプトとしてもemacs lispを使っています(cgi的なことにschemeを使うつもりですが…)。

前のmewのスクリプトの話ですが、大学のサーバー(solaris)のemacsが若干いろいろとコンパイル設定がいじられているせいか、emacs -f mewとかしてもmewのバッファーに変えてくれなかったりすることが多分問題だったかと思います。mewを実行して→(switch-to-buffer "+inbox")とかを最初に入れていれば働いていたかもしれません。確かにマクロよりはちゃんとしたコードの方が好ましいかと思いますけど^^。mewのコミュでなく、こっちで聞けばよかったです><。
はい、そのスレッドというか、そのトピです。
反応してくださって、ありがとうございます。

私もロクにコマンドが書けなかった頃はキーボードマクロをエディットする機能
(edit-last-kbd-macro)からlisp式を取り出して、それをつなぎ合わせれば何と
かなるのでは?と思っていた時期がありました。そして、そうやってもがいてい
ても、結果はいつも何ともなりませんでした。

> 確かにマクロの方が短くて簡単でした。

UNIXの文化ではプログラム(またはスクリプト)を書くより、端末からコマンド
でやった方が簡単だったと苦笑することがよくあります。楽しいUNIXなどの本を
読むと書かれていることです。emacsでも同じですね。でもそういうのはプログ
ラムが書けるからそう言えるのであって、そうでない人には分からないことなん
です。

> mewのコミュでなく、こっちで聞けばよかったです><。

他のコミュではlispでプログラムを書いてみようという話題にはならないようで
すね。まあ、ここでも状況は同じかもしれません。それと、自分で書いたプログ
ラムをこういう場で晒すのに抵抗を感じる人も居ると思います。

自分のコードを晒すのはイヤだと言っても、もしその人がプロのプログラマのタ
マゴだとしたら、将来はイヤでもそうすることになります。そして先輩や上司か
ら立ち直れないようなコメントをいただくことになるかもしれません。それに比
べたら、ここではみなさん温かい目で見てくれるのではないかと思いますが、い
かがでしょうか。それに、キツイことを言われたとしても、それはプログラムに
対してであって、それを書いた人を批判するものではないと思うんです。

今ちょうど別のトピでメールを飛ばすプログラムを書く話題になっているので、
宜しければご参加ください。
というか若干古いですがw、#2、3の課題、自分なりのコードも書いてみました^^。
string-matchを使って入力ミスがあるかどうか確認するというのが考えていませんでしたが、確かにあった方がイイかなとあとで追加しちゃいました。
「,」ごと切ったりとかという作業はしていないですが、書いたのも初心者なものでわかりやすいと思うところがあるかもしれません…。
http://paste.lisp.org/display/114478
emacs --batch -Q -l diary-maker.el -f blog-makerでコマンドラインから実行するとスクリプトとしてきれいに動いてくれます。

そうですね、mixiのこういうコミュはlispだけでなく、linuxとかもあまり盛り上がらないんですね。特にlispのような比較的に人気のない言語なら、ircのチャンネルやlinuxquestions.orgとかでしか話せないような気が…。僕の経験からはですね。大学でもほとんど知られていないんですし。
数少ない人数ですが、lispでなんかやっている人とか盛り上げましょう><。
blog-makerを動かしてみました。

blog.txtが空の場合に、char-afterがwrong-type-argument number-or-marker-pに
なるようですが、何か操作上の注意事項があれば教えてください。

tanaka@ubuntu:~/elisp$ emacs --batch -Q -l test1.el -f blog-maker
date?: 2010-09-13
Title for new entry?: New
Contents: I am a boy.
Wrong type argument: number-or-marker-p, nil
あ、ということは私が書いたコードも問題ありですかね・・・
まだ確認してませんが・・・(^^;
原作?がstdioという訳の分からないライブラリもどきを前提にしていたので書
き直してみました。Emacsコマンド、スクリプト、どっちでも動くと思います。

(require 'cl)

(defun blogman ()
 (interactive)
 (let* ((buffer (find-file-noselect (expand-file-name "Blog.txt")))
     (string (save-excursion
          (set-buffer buffer)
          (buffer-string)))
     (contents-list (mapcar '(lambda (line)
                  (split-string line ","))
                (delete "" (split-string string "\n"))))
     (date (read-string "日付を入力してください(ex 2006-01-01): "))
     (output nil))
  (cond ((string-match "^[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]$" date)
      (let ((line (assoc date contents-list)))
       (if line (setq output (list line))
        (let* ((title (read-string "題名: "))
           (text (read-string "内容: "))
           (contents (list date title text)))
         (set-buffer buffer)
         (goto-char (point-max))
         (insert (mapconcat 'concat contents ",") "\n")
         (save-buffer)
         (setq output (list contents))))))
     ((string= "list" date)
      (setq output (sort contents-list '(lambda (a b)
                        (string< (car a) (car b))))))
     (t (error "入力エラー!")))
  (dolist (line output)
   (message (apply 'format "日付: %s\n題名: %s\n内容: %s\n\n" line)))))


tanaka@ubuntu:~/elisp$ emacs --batch -Q -l test2.el -f blogman
日付を入力してください(ex 2006-01-01): 2010-09-13
題名: New
内容: I am a boy.
Saving file /home/tanaka/elisp/Blog.txt...
Wrote /home/tanaka/elisp/Blog.txt
日付: 2010-09-13
題名: New
内容: I am a boy.


tanaka@ubuntu:~/elisp$ emacs --batch -Q -l test2.el -f blogman
日付を入力してください(ex 2006-01-01): 2010-09-12
題名: Last day
内容: I was a girl.
Saving file /home/tanaka/elisp/Blog.txt...
Wrote /home/tanaka/elisp/Blog.txt
日付: 2010-09-12
題名: Last day
内容: I was a girl.


tanaka@ubuntu:~/elisp$ emacs --batch -Q -l test2.el -f blogman
日付を入力してください(ex 2006-01-01): list
日付: 2010-09-12
題名: Last day
内容: I was a girl.


日付: 2010-09-13
題名: New
内容: I am a boy.


tanaka@ubuntu:~/elisp$ emacs --batch -Q -l test2.el -f blogman
日付を入力してください(ex 2006-01-01): 2010-09-12
日付: 2010-09-12
題名: Last day
内容: I was a girl.


tanaka@ubuntu:~/elisp$
さすがに。イャ〜、僕ファイルがない場合のこと全く考えていなくて^^。そうですね、新しいbufferだと(= ?\n (char-after (- (point) 1)))のif文(number-or-maker-p)でエラーを返しますね。
condition-caseを使って、エラーをキャッチしましたので、これでファイルが存在しない場合でもちゃんと新しく書いてくれます^^。
http://paste.lisp.org/+2GC4
(ファイルが存在しない場合)
riki@burnacid:~/temp/lq$ emacs --batch -Q -l diary-maker.el -f blog-maker
date?: list

""
riki@burnacid:~/temp/lq$ emacs --batch -Q -l diary-maker.el -f blog-maker
date?: 2010-09-13
Title for new entry?: date
Contents: date with Cindy
Wrote /home/riki/temp/lq/blog.txt
riki@burnacid:~/temp/lq$ emacs --batch -Q -l diary-maker.el -f blog-maker
date?: list

"2010-09-13,date,date with Cindy
"
riki@burnacid:~/temp/lq$ emacs --batch -Q -l diary-maker.el -f blog-maker
date?: 2010-09-13
2010-09-13,date,date with Cindy

というか、僕common-lispのライブラリを使ったことがありませんが、上記のコードだと、どこで使っていますか?
えっと、この場合はファイルがない場合ではなく、blog.txtのバッファが空だっ
た場合だと思います。ファイルがあっても、バッファが空になる場合はあり得
ますから。

で、私はそれを直せと言ったつもりはなくて、使用条件を教えてくださいと言
いました。つまり「blog.txtにはすでに1個以上の情報があることが前提です」
というレスポンスを予想していました。

それよりもchar-afterを使って何を調べているのか分かりませんでした。調べ
る必要があるんでしょうか?

そもそも私とは処理方針がかなり違いますね。zerocoolさんの場合は、すべて
をバッファ上で処理していますが、私の場合は最初にすべてを読み込んでリス
ト化しています。blog.txtがCSVでなくても良ければ、ファイルにリストをプリ
ントすると思います。そうすれば、CSVをリストにする処理は不要になり、ファ
イルを開いてreadするだけになります。

どちらの処理方針が良いかは、人それぞれということになると思います。

> というか、僕common-lispのライブラリを使ったことがありませんが、上記の
> コードだと、どこで使っていますか?

たぶんdolistはそうだと思います。clが必要ない書き方も可能ですが、最近は
dolistをよく使います。たかがそんなことのためにclをロードするな!という
人も居るでしょうね。そういう方は、ご自分のプログラムではそうしてくださ
れば、それで良いと思います。
ファイルがあって、バッファが空になる場合…ロックされた場合とかですか?そういう経験がないので、ファイルという表現にしました。

もちろん、そうですが、確かに課題文を読めば、追加可能にするということで、ファイルが存在しない場合でも追加できないとまずいんじゃないかとその指摘で思いました。どうせ1,2行で済むものですし、condition-caseはみたことがあったが、実際に使うの初めてですから、やってみたかったです^^。

そうですね、方針がこんなに違って作れるのもemacs lispの良いところかと思いますし、やっぱりいろんな書き方はあるはずですね。
dolistは確かにemacs lispのマクロかと思いますので、よくわかりませんが、emacs lisp以外にschemeしかできませんので、少しcommon lispについて調べようかと思います^^。

そうですね、そのchar-afterでnewline文字かどうか調べるのは、もしかしたら"...nantokaEOF"で終わるファイルもあるかと思ったからです。
たまに、ファイルを編集してると、改行して保存するのでなく、なんかを追加してそのまま保存したりして、そういうファイルができてしまいます。その場合はそのまま追加すると「日付、タイトル、内容日付、タイトル、内容」のような変な順になってしまいますから…。newlineがないと、追加してから文を入れるようなコードにしました。自分のくせのせいかもしれませんね><。ファイルをずっとスクリプトからでなく、たまに編集することがあるなら、そういうコードが必要かと思います。
まぁそれもアップローチが違うからってのもありますけど^^僕はあまりきれいに出力するようにフォーマッティングもせず、そのまま日付のある行を出力というチョット荒っぽい感じに出していますね。あまり行数が多いと読むの疲れそうですから。

どっちにしても、さすがに課題問題を越えてきたかと思いますw。
> ファイルがあって、バッファが空になる場合…ロックされた場合とかですか?
> そういう経験がないので、ファイルという表現にしました。

ゼロバイトのファイルが存在した場合ですね。で、いずれにしてもファイルが
存在するかどうかは気にしていません。気にするのならfile-exist-pか何かで
調べるべきです。そういう意図で、find-file-noselectを使っているつもりで
す。

> もちろん、そうですが、確かに課題文を読めば、追加可能にするということ
> で、ファイルが存在しない場合でも追加できないとまずいんじゃないかとそ
> の指摘で思いました。どうせ1,2行で済むものですし、condition-caseはみた
> ことがあったが、実際に使うの初めてですから、やってみたかったです^^。

なるほど・・・。そういうことは往々にしてありますね。

> そうですね、方針がこんなに違って作れるのもemacs lispの良いところかと
> 思いますし、やっぱりいろんな書き方はあるはずですね。dolistは確かに
> emacs lispのマクロかと思いますので、よくわかりませんが、emacs lisp以
> 外にschemeしかできませんので、少しcommon lispについて調べようかと思い
> ます^^。

プログラムである以上データの流れが分かる作りにしたい、というのが私の方
針です。なので、私のプログラムはエディタマクロっぽくないと思います。元々
がelisperでないのなら、そうなるんじゃないかという気がするのですが・・・
その辺がちょっと不思議です。自分の編集操作に忠実に作ったということです
かね?

> そうですね、そのchar-afterでnewline文字かどうか調べるのは、もしかした
> ら"...nantokaEOF"で終わるファイルもあるかと思ったからです。たまに、ファ
> イルを編集してると、改行して保存するのでなく、なんかを追加してそのま
> ま保存したりして、そういうファイルができてしまいます。その場合はその
> まま追加すると「日付、タイトル、内容日付、タイトル、内容」のような変
> な順になってしまいますから…。newlineがないと、追加してから文を入れる
> ようなコードにしました。自分のくせのせいかもしれませんね><。ファイ
> ルをずっとスクリプトからでなく、たまに編集することがあるなら、そうい
> うコードが必要かと思います。まぁそれもアップローチが違うからってのも
> ありますけど^^僕はあまりきれいに出力するようにフォーマッティングも
> せず、そのまま日付のある行を出力というチョット荒っぽい感じに出してい
> ますね。あまり行数が多いと読むの疲れそうですから。

そういう思いがあってやったことであれば良いんじゃないかと思います。

ただ私なら、condition-caseの中でchar-afterを使って調べるのではなく、
(point-max)のカラム位置がゼロかどうかを調べると思います。

> どっちにしても、さすがに課題問題を越えてきたかと思いますw。

そうですかね・・・。別に課題に縛られる必要はないと思いますが。
emacsコミュにこんな問題がありました。

「空白で区切った二つの自然数X、Yを読み込んで XからYまでを掛けた値を返すプログラムを作成せよ」

私の思考回路だと、どうしてもこうなってしまいます(^^;

(defun xy* (string)
(interactive "sスペースで区切った2つの自然数: ")
(let* ((value (mapcar 'string-to-number (split-string string)))
(x (apply 'min value))
(y (apply 'max value))
(xylist (list x)))
(while (< x y)
(setq xylist (cons (setq x (1+ x)) xylist)))
(message "%d" (apply '* xylist))))

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

Lispで書くテキスト処理 更新情報

Lispで書くテキスト処理のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。