JavaScript」タグアーカイブ

Escape

INI ファイルの読み書きページを更新しました。
INI ファイルの読み書き – Paepoi

セクションを見つける正規表現に最初戸惑った。

EXP = r'^\[\w+\]$'

でイケると思ったけど文字列に半角スペースがあると認識できない。
半角スペースを使うなで済ませようとも思ったけど。

EXP = r'^\[[^\]]+\]$'

そうだ「閉じブラケット以外の文字列なら何でもいい」にすれば!
こんなアホな思いつきに対応できる正規表現ってやはり面白い。

とほほの正規表現入門 – とほほのWWW入門
ところで、とほほさんで見た「ブラケット内は記号の意味を失う」なんですが。

#! /usr/bin/env python3

import re

# [..] にマッチさせる正規表現
EXP = r'^\[[^\]]+\]$'
# EXP = r'^\[[^]]+\]$' # Python OK

a = ['[test]', '[test2]', '[test3] ', ' [test4]', '[test 5]']

for s in a:
    if re.search(EXP, s):
        print(s)

Python

#! /usr/bin/env php

<?php

// [..] にマッチさせる正規表現
$EXP = '/^\[[^\]]+\]$/';
// $EXP = '/^\[[^]]+\]$/'; # PHP OK

$a = ['[test]', '[test2]', '[test3] ', ' [test4]', '[test 5]'];

foreach ($a as $s) {
    if (preg_match($EXP, $s))
        echo $s.PHP_EOL;
}
?>

PHP

#! /usr/bin/gjs

// [..] にマッチさせる正規表現
const EXP = /^\[[^\]]+\]$/;
//const EXP = /^\[[^]]+\]$/; // Gjs NO

let a = ['[test]', '[test2]', '[test3] ', ' [test4]', '[test 5]'];

for (let s of a) {
    if (EXP.test(s)) {
        print(s)
    }
}

Gjs ダメだった。

JavaScript エンジンは複数あるので全部かどうかは試していないけど。
エスケープすれば全部イケたのでブラケット内もエスケープしたほうがいいかと。

Dinamic Import: Gjs and JXA

現在の JavaScript はダイナミックインポートが可能。
下記ページで Chrome や Safari で動くと解りますね。

全モダンブラウザで使えるJavaScriptのdynamic import(動的読み込み) – Qiita

GNOME の Gjs は imports 関数があるので関係ないんだけど。
そういえば macOS の JXA はファイル分割ができないのが困る。
コレを利用してクラス毎に分割できるかな。

#!/usr/bin/osascript

import('./sub.js')
	.then((module) => {
        console.log('Start!');
		const sub = new module.Sub();
        sub.subMethod();
	});

main.js

export class Sub {
    subMethod() {
        console.log('this is Sub Class Method');
    }
}

sub.js

osa

なんでだよ!
Promise だと認識はしているけど動作しないってことみたい。
JavaScriptCore が全部やってくれるってわけじゃないんかい。

Gjs でも同じかな?
console.log を print に書き換えて実験。

#!/usr/bin/gjs

import('./sub.js')
	.then((module) => {
		const sub = new module.Sub();
        sub.subMethod(); 
	});

main.js

export class Sub {
    constructor(app) {
        print('Hello');
    }
    subMethod() {
        print("this is Sub Class Method");
    }
}

gjs

動いたのでコンストラクタも入れてみた、普通に Class ですね。
いや Gjs は imports を使ったほうが簡単ですけど。
というか、Apple は内製スクリプトには本当にヤル気が無いなって。

mpv @ Next File (Nautilus Sort)

しつこいようだけど mpv で次のファイルを再生させるスクリプト。
順番が Nautilus と同じでないのでイマイチ不便だなって。

だったらコレも作ってしまえ!
Gjs なり PyGObject なりでソートさせて出力するコマンドを。
mpv の拡張スクリプトでは無理なのでコマンドを自作する。
それを Lua で呼び出せばなんとかなるはず。

ついでに、いちいち拡張子を指定するのも面倒臭い。
てか Lua がショボいなら自作コマンドのほうで正規表現を使えばいい。
で、GNOME では動画ファイルの ContentType は以下のようになっている。

video/mp4
video/quicktime
video/x-matroska

ContentType なら先頭の video/ だけで動画ファイルを見分けできる。
ということでこんなスクリプトを書いてみた。

#!/usr/bin/gjs

if (ARGV.length == 0) {
    print('usage: nautilus_ls {DIRNAME}');
} else {
    const GLib = imports.gi.GLib;
    const Gio = imports.gi.Gio;
    const re = /^video\//;

    let files = [];
    let d = Gio.file_new_for_path(ARGV[0]);
    let ls = d.enumerate_children('standard::content-type', 0, null);
    for (;;) {
        let info = ls.next_file(null);
        if (info == null)
            break;
        let t = info.get_content_type();
        if (re.test(t))
            files.push(info.get_name());
    }
    files.sort((s1, s2)=> {
        let cmpstr1 = GLib.utf8_collate_key_for_filename(s1, -1);
        let cmpstr2 = GLib.utf8_collate_key_for_filename(s2, -1);
        if (cmpstr1 < cmpstr2)
            return -1;
        return 1;
    });
    print(files.join('\n'));
}

// ex: ft=js

Gjs での例。
nautilus_ls という拡張子無しファイル名でパスの通った場所に保存。
実行パーミッション追加でコマンドの出来上がり。
このコマンドを Lua で呼び出しする。

-- ~/.config/mpv/scripts/next_prev.lua

local utils = require 'mp.utils'

-- Ctrl+DOWN @ Next File Play
function on_nextfile()
    local hit = false
    local directory, fn = utils.split_path(mp.get_property('path'))
    if directory == '.' then
        directory = utils.getcwd()
    end
    local pfile = io.popen('nautilus_ls  "'..directory..'"')
    for filename in pfile:lines() do
        if hit then
            mp.commandv('loadfile', utils.join_path(directory, filename))
            if mp.get_property_bool('pause') then
                mp.set_property_bool('pause', false)
            end
            break
        end
        hit = filename == fn
    end
    pfile:close()
end
mp.add_key_binding('Ctrl+DOWN', 'nextfile_func', on_nextfile)

-- Ctrl+UP Previous File Play
function on_prevfile()
    local prevfn = ''
    local directory, fn = utils.split_path(mp.get_property('path'))
    if directory == '.' then
        directory = utils.getcwd()
    end
    local pfile = io.popen('nautilus_ls  "'..directory..'"')
    for filename in pfile:lines() do
        if filename == fn and prevfn ~= '' then
            mp.commandv('loadfile', utils.join_path(directory, prevfn))
            if mp.get_property_bool('pause') then
                mp.set_property_bool('pause', false)
            end
            break
        end
        prevfn = filename
    end
    pfile:close()
end
mp.add_key_binding('Ctrl+UP', 'prevfile_func', on_prevfile)

イケた!
GNOME 限定です、他の環境の人は参考程度に。

mpv @ Lua to Javascript

mpv を Lua で拡張するのが楽しい皆様。
こんなトコを見つけました。

GitHub – samhippo/mpv-scripts

参考になります、いやコピペでそのまま使ってもいいんだけど。
Windows 限定のコードが所々あるので macOS や Fedora の人は注意です。

そういえばこの人は複数拡張子のマッチをどうやっているんだろう?

mpv-scripts/next-file.lua at master ? samhippo/mpv-scripts ? GitHub

拡張子文字列で連想配列を作り値を全部 true に。

lua_nil

存在しなければエラーではなく nil になる、なるほど。
酷い手段だけど Lua 自体が色々とショボいからしかたがないか。

いやまて、この方法でディレクトリ内を列挙できるんだよな。
ls コマンドが不要なら正規表現が強力な Javascript を使うという手が。
とりあえず mp.utils を Javascript ではどう呼び出すか試す。

// ~/.config/mpv/scripts/test.js

function on_test() {
    //let dir = mp.utils.split_path(mp.get_property('path')); // ES5...
    var dir = mp.utils.split_path(mp.get_property('path'));
    mp.osd_message('Playng File: ' + dir[1]);
}
mp.add_key_binding('Ctrl+3', 'test_func', on_test);

なんだ、ドットで普通に使えるヤン。
しかし let 宣言でエラー、まさか今更 ECMAScript 5…

mpv.io

mpv.io にも書いていた、for-of とかも当然使えないな。
ES5 でも正規表現は同じはずだ、使ってみる。
以前書いたディレクトリ内で次のファイルを js で丸ごと書き換え。

// ~/.config/mpv/scripts/next_prev.js

var re = /\.(mov|m4v|mp4)$/i;

// Ctrl+DOWN でディレクトリ内の次ファイルを再生
function on_nextfile() {
    var dir = mp.utils.split_path(mp.get_property('path'));
    // カレントディレクトリだとドットになるので
    if (dir[0] == '.') dir[0] = mp.utils.getcwd();
    // ls
    var ls = mp.utils.readdir(dir[0], 'files');
    ls.sort();
    if (mp.last_error() == '') {
        // for-of が使いたい...
        var len = ls.length;
        var ex = false;
        for (var i=0; i<len; i++) {
            var f = ls[i];
            if (re.test(f) && ex) {
                mp.commandv('loadfile', mp.utils.join_path(dir[0], f));
                if (mp.get_property_bool('pause'))
                    mp.set_property_bool('pause', false);
                break;
            }
            ex = f == dir[1];
        }
    }
}
mp.add_key_binding('Ctrl+DOWN', 'nextfile_func', on_nextfile);

// Ctrl+UP でディレクトリ内の手前ファイルを再生
function on_prevfile() {
    var prevfn = '';
    var dir = mp.utils.split_path(mp.get_property('path'));
    if (dir[0] == '.') dir[0] = mp.utils.getcwd();
    var ls = mp.utils.readdir(dir[0], 'files');
    ls.sort();
    if (mp.last_error() == '') {
        var len = ls.length;
        var ex = false;
        for (var i=0; i<len; i++) {
            var f = ls[i];
            if (re.test(f)) {
                if (dir[1] == f && prevfn != '') {
                    mp.commandv('loadfile', mp.utils.join_path(dir[0], prevfn));
                    if (mp.get_property_bool('pause'))
                        mp.set_property_bool('pause', false);
                    break;
                }
                prevfn = f;
            }
        }
    }
}
mp.add_key_binding('Ctrl+UP', 'prevfile_func', on_prevfile);

動くジャン。
ただ ls と違ってソートしないとよくワカラン順番になるみたい。

loadfile は半角スペース付きでもダブルクォートで囲む必要は無かったのね。
というか URI にする必要すら無かった、とほほ。

とにかくコレで完璧な拡張子判別ができるようになった。
慣れた言語はやっぱり楽だね、言語仕様を調べる必要が無いし。
自由に改造して使ってください、Windows でも多分動くと思う。

GNOME 3.38 Gjs

すっかり遅くなってしまったけど、GNOME 3.38 の変更点。
筆者に関係ありそうなのは Gjs だけだな。

開発者、システム管理者向けの新規事項

String.replaceAll() なんかはメソッド名で別るんだけーがさぁ。
?? と ?. オペレーターの追加、とあるけど説明無し、何だよコレ。
「 javascript nullish check 」で検索。

JavaScriptのOptional ChainingとNullish Coalescing Operatorでnullやundefinedと戦う

#!/usr/bin/gjs
 
//const p = console?.log ?? print;  // Error
const p = this.console?.log ?? print;
p("SUZUKIS Motorcycle is Cool!");

Gjs には console オブジェクトが無い、ということで単純にやってみた。
オブジェクトを直接 (undefined|null) かどうかは調べられないのね。
プロパティが (undefined|null) かどうかのチェックということね。
グローバルオブジェクトはルートの this から辿れる、いやこんな使い方普通はしない。

#!/usr/bin/gjs

if (typeof console === 'undefined')
    print('print');
else
    console.log('console');

undefined だけなら昔ながらの方法があるし、筆者も使っていた。
null かどうかも調べたい時に or 演算する手間が省けるようです。
というかコレ ES2020 の新規機能ってことみたい。

JavaScriptの次の仕様ES2020で追加されることが決定した新機能まとめ – ICS MEDIA

これ以外の ES2020 も使えるかテスト。
import 関数は使えない。
Promise はエラー、よくわからない。
matchAll は動く、Gjs では詳細は出力されないけど。
globalThis は Gjs では関係ない、てか this でよくね?
BigInt は GNOME 3.36 で既に対応していた。

ということで、今日の木曽川。

tsugumi

ツグミ、でかいスズメじゃないよ冬しかいないよ。

kogera

コゲラ、この可愛らしさでキツツキってのがまた。

enaga

エナガ、シジュウカラやメジロと混群していた。

今日はカメラを持った人を結構見た、巨大な白レンズも何人か。
けれど皆カモばかり撮っていた、小鳥も沢山いるのにもったいない。
てか爺さんばかり、なんか道の駅のバイク置き場カヨって感じ。
若い人も電車やコスプレばかりじゃなく小鳥も撮ろうよ。