GRegex

正規表現に実は今まで興味が無かった。
実際に知らなくても特に何も困らなかった。

でもパターンの書き方を何かの言語で覚えてしまえば他で使い回せる。
他の言語はもとより grep コマンドでさえ、と今頃知った。
これは勉強しといたほうが良いかも。

でも使う手段は言語によって違うんだよなぁ。
いっそ GLib で使えればどんな言語でも gir で同じ手段でイケるのに。

Perl-compatible regular expressions: GLib Reference Manual

って普通にあるじゃん、perl と同じってことね。
Gjs でコイツと JavaScript の RegExp を比べてみよう。

正規表現 – JavaScript | MDN

画像の拡張子が最後に付いているかを大小文字区別なく探すコード。

#!/usr/bin/gjs

const GLib = imports.gi.GLib;

const ARRAY = ["001.jpg", "002.JPEG", "003.Png", "004.gif", "jpeg.gif"];
const PATTERN = "\.(jpe?g|png)$";

// JavaScript RegExp
ARRAY.forEach(function(s) {
    let re = new RegExp(PATTERN, "i");
    print(re.test(s));
});

print("----------");

// GLib Regex
ARRAY.forEach(function(s) {
    print(GLib.Regex.match_simple(PATTERN, s, GLib.RegexCompileFlags.CASELESS, 0));
});

/* @ Python
import re
for s in ARRAY:
    res = True if re.search(PATTERN, s, re.I) else False
    print(res)
*/

/* output
true
true
true
false
false
----------
true
true
true
false
false
*/

うん、見事に同じパターンが使えるのね。
コレで Vala だろうが何だろうが同様に使える。

Python は真偽値を戻さず mach Object 自体が True って変。
そりゃ Python なんだから変だと言われても何を今更と思えるのが凄い。

bracket

明けましておめでとうございます。

と、いうことで。

括弧 – Wikipedia
マジですか!えぇ…

( = パーレン (paren) # 小括弧
[ = ブラケット (bracket) # 大括弧
{ = ブレース (brace) # 中括弧

が 2017 年初っ端な現在の常識なの?

上から順に「括弧、角括弧、中括弧」と 15 年間読んでいや筆者は…
グローバルにも程があるだった、どの宗教にも合致しネェや!
いったい何の影響でこんなヒネクレたのかはシラネ、これが今の自分。

元旦に更新した ShellScript Tips も中括弧って表現を多用した。
だってさ、ついさっきまでソレが当然だと思っていたんだモン!

と、いうことで。
今年もよろしくお願いします。

bash =~

sh では存在しないコマンドを打つとなんか調べてくれる。
あれは command-not-found というものが行っているらしい。

Linux入門はじめますた: おせっかいな「command not found」

Fedora 25 で調べると以下のバイナリだった。
/usr/libexec/pk-command-not-found

ハンドラの定義は set コマンドで見ることができる。
随分違うなぁ、まあ 7 年も前の記事ですし。

どっちにしろ無効にしたい場合はやることは同じ。
command_not_found_handle 関数を ~/.bashrc で上書き…

いやチョットまて?

=~ 演算子って何だ!!!

Man page of BASH

にて =~ でページ内検索でなんとか。
正規表現マッチってことみたい。

だけど上記関数は i という文字が含まれているかどうかだけだよな?
それなら単純に文字列が含まれているかどうかも解るかも。

おぉ、Python の文字列 in 演算子のように使えるジャン!
こんな便利な使い方が検索で全然出てこないのは何故だYO!

GSubprocess and Python subprocess

GSubprocess: GIO Reference Manual
あれ、こんなのあったんだ。

これを使えば Gjs からでも Python の subprocess と同様なことができるかも。
subprocess を使って筆者が作っている Comipoli beta9 で一部を書き換えしてみた。

class ComipoliWindow(Gtk.ApplicationWindow):
    def __init__(self, app):
        Gtk.ApplicationWindow.__init__(self, application=app)
        GtkClutter.init();
        # etc...

    def iter_7z(self):
        result, output, error, status = GLib.spawn_command_line_sync('7za l -slt "{0}"'.format(self.cbzpath))
        lines = output.decode("utf-8").split("\n")
        for line in lines:
            if line.startswith('Path'):
                name = line[7:]
                ext = os.path.splitext(name)[1].lower()
                if ext == ".jpg" or ext == ".jpeg" or ext == ".png":
                    #with subprocess.Popen(["7za", "x", "-so", self.cbzpath, name], stdout=subprocess.PIPE) as proc:
                    #    data = proc.stdout.read()
                    #    yield self.data_to_pixbuf(data)
                    sp = Gio.Subprocess.new(["7za", "x", "-so", self.cbzpath, name], Gio.SubprocessFlags.STDOUT_PIPE)
                    stream = sp.get_stdout_pipe()
                    p = GdkPixbuf.Pixbuf.new_from_stream(stream)
                    if p.get_height() > 1080:
                        rate = p.get_width() / p.get_height()
                        p = GdkPixbuf.Pixbuf.scale_simple(p, 1080 * rate, 1080, GdkPixbuf.InterpType.BILINEAR)
                    stream.close()
                    yield p

    def iter_zip(self):
        with zipfile.ZipFile(self.cbzpath) as o:
            l = o.namelist()
            l.sort()
            self.datas.clear()
            for name in l:
                ext = os.path.splitext(name)[1].lower()
                if ext == ".jpg" or ext == ".jpeg" or ext == ".png":
                    data = o.read(name)
                    yield self.data_to_pixbuf(data)

    def data_to_pixbuf(self, data):
        stream = Gio.MemoryInputStream.new_from_data(data)
        p = GdkPixbuf.Pixbuf.new_from_stream(stream)
        if p.get_height() > 1080:
            rate = p.get_width() / p.get_height()
            p = GdkPixbuf.Pixbuf.scale_simple(p, 1080 * rate, 1080, GdkPixbuf.InterpType.BILINEAR)
        stream.close()
        return p

動くじゃん。
しかもほとんど同じ!

ただ何故か g_subprocess_newv の引数が new メソッドに割り当てされている。
Gjs リファレンス同様に Property 割り当てで作ったほうが違和感が少ないかと。
PyGObject では JSON をイコールにするだけ。

// Gjs
let sp = new Gio.Subprocess({
    argv: ["7za", "x", "-so", self.cbzpath, name],
    flags: Gio.SubprocessFlags.STDOUT_PIPE
});

たぶんこれでいい。

一旦バイナリを取り出しせずに直接ストリームにできるからこのほうが効率いいかも。
でもそう書き換えると CBZ の処理側を作り替えしなきゃいけないけどどうしよう?

GLib, Gio はまだまだ知らないことがイッパイあると思い知る今日この頃です。

CB7

先日 gnome-autoar というのを見つけた。
けれどソースコードには肝心の圧縮展開を行うコードは無かった。

GitHub – GNOME/gnome-autoar: Automatic archives creating and extracting library

中身をよく見ると archive.h を include している。
どうやら圧縮展開は libarchive 依存のミドルウエアってことみたい。

てゆーか libarchive って今は 7z 圧縮に対応しているってことかYO!

libarchive – C library and command-line tools for reading and writing tar, cpio, zip, ISO, and other archive formats @ GitHub

でも CB7 を作っても Nautilus 上でサムネイルされない。
おいおいマジで圧縮展開だけなのかよ。

いや、コミックブックアーカイブって五種類もあったのね。
ACE なんて見たことが無いし TAR はコレだけだと非圧縮だし無視でいいと思うが。

Comic book archive – Wikipedia

Evince でも CBR, CBZ, CB7 の三つをサポートしているみたい。
だけど Evince はどうやら p7zip 依存のようだ。
それに 7z だと file-roller で開くことができない、こいつも同様か。

ということで、現状では p7zip を入れておかないと色々不便だ。

sudo dnf install p7zip

United RPMS は unrar はあるけど rar は無いことに今頃気が付く。
コイツは削除して RARLAB のを自分で入れる。

よし3形式ともサムネイルとプレビューができるようになったぞ。
Evince, file-roller も対応、後は我がアプリ。
CBR と同じ方法でイケた、つーことで更新。

結局 gnome-autoar はどうでもよかった。
サムネイル表示されないのではビューアを作っても虚しいもんね。