秀丸で開いたファイルのフォルダにUbuntuを開いて移動する

これは、昔からコマンドプロンプトでよくやっていた。例えばPythonのコードを書いて、さあ実行しようという時に、コマンドプロンプトを起動して、Change Directoryする。しかし、わざわざ分かっているディレクトリに手動で移動するのは面倒ではないか。

コマンドプロンプトには/Kというオプションがあって、そのあとに書かれたコマンドをコマンドプロンプトを開いた後に実行する。なので、

cmd.exe /k cd dicrectory

とすれば、コマンドプロンプトが起動してそのディレクトリに移動する。

TeraTermには起動時にマクロを実行する機能があって、ログインして、子サーバにSSHでログインして、Sambaで開いていたファイルのフォルダにChange Directoryするようにしていた。

しかし、Windows 10のUbuntuは簡単にはうまくいかない。今回一念発起してその機能を実現させたので紹介する。

秀丸マクロ

JScriptで書かれたスクリプトWindows Script Hostで実行する。その際、秀丸のファイルのフォルダをdirectory2で拾って、引数にする。

パスの変更

例えば、Windowsの「C:\Users\user」というパスはUbuntu上では「/mnt/c/Users/user」となるので、この変換を行う。

function convert_windows_dir_into_Linux_dir(dir) {
	var v = dir.split("\\");
	v[0] = "/mnt/" + v[0].charAt(0).toLowerCase();
	return v.join("/");
}

Ubuntuの実行

Ubuntuの実行はstartコマンドでおこなう。

var Shell = WScript.CreateObject("WScript.Shell");
var command = "cmd.exe /c start ubuntu";
Shell.Run(command, 1, true);

Ubuntuが開いたらChange Directoryしたいが、やり方がわからない。しょうがないので、クリップボードを使ってペーストする。

clipというコマンドがあるので、そこに流し込む。例えばコマンドプロンプトで、

echo abc| clip

と打つと、クリップボードに"abc\n"が貼り付けられる(どうしても改行コード込みになってしまうようだ)。これを利用して、

Shell.Exec("cmd /c echo cd " + Linux_dir + "| cmd /c clip");

として、Linux形式に変換したディレクトリをクリップボードに貼り付ける。
このあと、SendKeysでそのディレクトリをUbuntuに貼り付けられるようにUbuntuの設定を変更する。Ubuntuを開いて、左上をクリックして「プロパティ」から設定画面を表示させる。

f:id:inamori:20190809094413p:plain

「編集オプション」の「Ctrlキー ショートカットを有効にする」をチェックすればよさそうだが、なぜかそれではうまくいかない。ここでは、「Ctrl+Shift+C/Vをコピー/貼り付けとして使用する」をチェックする。

そうして、SendKeysを使う。

WScript.Sleep(1000);
Shell.SendKeys("+^V");

この秀丸マクロをショートカットキーに登録しておけばよいだろう。
サクラエディタ等でも同様に可能だと思われる。

JuliaでProject Euler(22)

Problem 42

https://projecteuler.net/problem=42

function read_names(path)
    open(path, "r") do fp
        for line in eachline(fp)
            return [ s[2:length(s)-1] for s in split(line, ",") ]
        end
    end
end

function is_square(n)
    return Int(floor(sqrt(n)))^2 == n
end

function is_triangle(n)
    # x^2 + x = 2n
    # x = (-1 + sqrt(1 + 8n)) / 2
    return is_square(1 + 8n)
end

function word_score(word)
    return sum(Int(c)-Int('A')+1 for c in word)
end

function read_words(path)
    open(path, "r") do fp
        for line in eachline(fp)
            return [ replace(s, "\"" => "") for s in split(line, ",") ]
        end
    end
end

function e042(path)
    words = read_words(path)
    return sum(1 for word in words if is_triangle(word_score(word)))
end

path_names = ARGS[1]
println(e042(path_names))

Float64をInt64に変換するとき、わざわざ小数点以下が0の浮動小数点数にしてからでないと変換できない。

replaceの引数は、文字列と文字列ではなく、文字列のPair。古いバージョンだと違うので注意。

JuliaでProject Euler(20)

Problem 25

https://projecteuler.net/problem=25

function add(v1, v2)
    if length(v1) > length(v2)
        return add(v2, v1)
    end
    v3::Array{Int} = []
    carry = 0
    for k in 1:length(v1)
        n = v1[k] + v2[k] + carry
        carry = div(n, 10)
        d = n % 10
        push!(v3, d)
    end
    
    for l in length(v1)+1:length(v2)
        n = v2[l] + carry
        carry = div(n, 10)
        d = n % 10
        push!(v3, d)
    end
    if carry > 0
        push!(v3, carry)
    end
    return v3
end

fibs() = Channel() do c
    a, b = [1], [1]
    push!(c, a)
    while true
        a, b = b, add(a, b)
        push!(c, b)
    end
end

function e025(N)
    x = first(Iterators.filter(x -> length(x[2]) == N, enumerate(fibs())))
    return x[1]
end

N = parse(Int, ARGS[1])
println(e025(N))

fibsの部分は次のようにも書ける。

function fibs(c::Channel)
    a, b = [1], [1]
    push!(c, a)
    while true
        a, b = b, add(a, b)
        push!(c, b)
    end
end

function e025(N)
    x = first(Iterators.filter(x -> length(x[2]) == N,
                            enumerate(Channel(c -> fibs(c)))))
    return x[1]
end

関数っぽくなるが、だいぶ長くなる。

JuliaでProject Euler(19)

Problem 22

https://projecteuler.net/problem=22

function read_names(path)
    open(path, "r") do fp
        for line in eachline(fp)
            return [ s[2:length(s)-1] for s in split(line, ",") ]
        end
    end
end

function name_score(name)
    return sum(Int(c)-Int('A')+1 for c in name)
end

function e022(path)
    names = sort(read_names(path))
    return sum(k*name_score(name) for (k, name) in enumerate(names))
end

path_names = ARGS[1]
println(e022(path_names))

ファイルを読むのは上のよう。Pythonに似ているといえば似ている。

JuliaでProject Euler(18)

Problem 20

https://projecteuler.net/problem=20

Problem16とだいたい同じ。

Pythonで書くと、

from itertools import *
import sys

def multiply(v, n):
    v2 = []
    carry = 0
    for d in v:
        carry, r = divmod(d*n+carry, 10)
        v2.append(r)
    while carry > 0:
        carry, r = divmod(carry, 10)
        v2.append(r)
    return v2

def e020(N):
    a = [1]
    for n in range(1, N+1):
        a = multiply(a, n)
    return sum(a)

N = int(sys.argv[1])
print e020(N)

これをJuliaに翻訳して、

function multiply(v, n)
    v2::Array{Int} = []
    carry = 0
    for d in v
        m = d*n+carry
        r = m%10
        carry = div(m, 10)
        push!(v2, r)
    end
    while carry > 0
        r = carry%10
        carry = div(carry, 10)
        push!(v2, r)
    end
    return v2
end

function e020(N)
    a = [1]
    for n in 1:N
        a = multiply(a, n)
    end
    return sum(a)
end

N = parse(Int, ARGS[1])
println(e020(N))

やはり、2行目で型指定していないと遅い。
PyPyで、

$ time pypy e020.py 30000
511470

real    0m15.933s
user    0m13.875s
sys     0m2.016s

Juliaで型指定しないと、

$ time julia e020.jl 30000
511470

real    2m6.301s
user    2m3.984s
sys     0m0.594s

上のように型指定すると、

$ time julia e020a.jl 30000
511470

real    0m10.654s
user    0m10.734s
sys     0m0.500s

PyPyより速くなった。

JuliaでProject Euler(17)

Problem 17

https://projecteuler.net/problem=17

何度も解いているが、一度も最初で正しい答えを出した記憶がない。
できるだけ再帰を使う。

function e017(N)
    function num_length(n)
        if haskey(num_letters, n) && n < 100
            return length(num_letters[n])
        elseif n < 100
            d = n%10
            return num_length(n-d) + num_length(d)
        elseif n < 1000
            d = div(n, 100)
            r = n%100
            if r == 0
                return num_length(d) + length(num_letters[100])
            else
                return num_length(d*100) + 3 + num_length(r)
            end
        else
            d = div(n, 1000)
            r = n%1000
            if r == 0
                return num_length(d) + length(num_letters[1000])
            else
                return num_length(d*1000) + 3 + num_length(r)
            end
        end
    end
    
    num_letters = Dict(
        0 => "", 1 => "one", 2 => "two", 3 => "three", 4 => "four", 5 => "five",
        ...
    )
    
    return sum(num_length(n) for n in 1:N)
end

N = parse(Int, ARGS[1])
println(e017(N))