htsign's blog

ノンジャンルで書くつもりだけど技術系が多いんじゃないかと思います

以後は特に指定のない限りJSはES6記法で書いていこうと思います。

Intlオブジェクトというものを知りました。
国際化表記における各種変換を取りまとめるそこそこ大規模なオブジェクトらしい。

Collator DateTimeFormat NumberFormatの3つのサブオブジェクトを持つ模様。
それぞれインスタンス化して使用するっぽい。

(() => {
  let localeOption = { style: "currency", currency: "jpy" };
  let locale = new Intl.NumberFormat("ja-JP", localeOption);
  console.log(locale.format(1234500)); // => ¥1,234,500
})();

便利。

第二引数のoptionにcurrencyDisplayを指定すると表記方法が変わるっぽい。
currencyDisplay: "symbol"がデフォルトで、他にcodenameがあるらしい。
symbolの場合の記号が半角とか全角とか、その辺は実装依存っぽい。

とか思ってたら

Number#toLocaleStringとか、他の代表的なオブジェクトにメソッドとして同等機能が提供されていた。
newはオーバーヘッドも大きいし*1、特別な理由がない限りは基本こっちですね。

*1:実測はしていませんが

グローバルIPアドレスを得る

今まではipifyを使っていました。

> Invoke-WebRequest api.ipify.org | Write-Host
125.203.***.***

非常にシンプルで使用制限もなく応答速度も問題なくて重宝していました。


これで終わりでいいんですが、みんな大好きStackOverflowのとあるスレッドで有用なやり取りがあったので。
Getting my public IP via API - Stack Overflow

どうやらipinfo.ioというのがあるようで、「1日1000リクエストまで」という制限があるようですが*1柔軟性が高いです。
オプションを何もつけなければJSONでデータが返ってきます。

> Invoke-WebRequest ipinfo.io | Write-Host
{
  "ip": "125.203.***.***",
  "hostname": "i125-203-(中略).ap.plala.or.jp",
  "city": "",
  "region": "",
  "country": "JP",
  "loc": "35.***,139.***",
  "org": "AS4713 NTT Communications Corporation"
}

まぁ使い方は公式サイトにでかでかと書かれてるのでわざわざここで説明するまでもないんですが、JSONのプロパティがオプション名になってます。

> Invoke-WebRequest ipinfo.io/ip | Write-Host
125.203.***.***

> Invoke-WebRequest ipinfo.io/country | Write-Host
JP


特に凝ったことするのでなければipify, ちょっと別の情報も使いたいってときはipinfo.ioって具合に使い分けましょうかね。

*1:無料プランでの話なので、有料プランを選べばもちろん制限は緩くなります。

OSXのバージョンを確認する方法

ただ単に今駆動しているOSXのバージョンを確認するだけなら

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.10.5
BuildVersion:   14F1605

で終わりです。

今回はとあるパーティションにインストールされているOSXのバージョンを外部から確認する方法です。
ある方から起動できなくなったHDDにインストールしたOSXのバージョンを確認してほしい、との依頼があったために調べて知った方法です。
要するに一部のLinuxディストリで言うcat /etc/*-releaseのようなものです。

まずは目的のパーティションに移動します。

$ cd /Volumes/Machintosh\ HD/

その上で、そのパーティション上の/System/Library/CoreServices/の中にあるSystemVersion.plistにバージョン情報が書かれています。

$ cat System/Library/CoreServices/SystemVersion.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
        <key>ProductBuildVersion</key>
        <string>14F1605</string>
        <key>ProductCopyright</key>
        <string>1983-2016 Apple Inc.</string>
        <key>ProductName</key>
        <string>Mac OS X</string>
        <key>ProductUserVisibleVersion</key>
        <string>10.10.5</string>
        <key>ProductVersion</key>
        <string>10.10.5</string>
</dict>
</plist>

ちなみに、ここのXMLを書き換えることで「このMacについて」で表示されるバージョン情報を偽装することができるようです。

参考: Tutorial: Change the OS X Version by modifying systemversion.plist

久しぶりにPC周りのお買い物

ついに買いました。TLCSSD
nttxstore.jp

思えばSLCで容量40GBしかないのを買って、MLCだけど容量60GBしかないのを買って、MLCで容量120GBのを買って、MLCで256GBのを買って、今度のやつで5枚目です。
SandForce製とかいう0Fill, 1Fill以外まるで速度の出ないゴミみたいなコントローラ載っけてたのもありました。今は外付けケースに入れてポータブルになってますが使ってません。

Steamのゲームをいくつか置いとくだけなので、そこそこの容量とそこそこの読み込み速度があれば役に立ってくれると信じてる。

ベンチマークスコア

f:id:htsign:20160108012118p:plain
公称値はSeqRead 540MB/s SeqWrite 470MB/sなので、書き込みはともかく読み込みはまずまずの速度じゃないかと思います。
他所のレビューではスコアがもう少しよかったので、単純にSBチップやSATAケーブルがアレだったかも。
ケーブルくらいは近いうちに買い替えます。

Microsoft Edge (Windows 10 Mobile) のUser-Agent

なかなかすごいことになっています。
どこかの記事(確かスラド辺り)で読んだことありますが、WebKitと同じ挙動を示すようにしたとかなんとか。

Lumia 950で確認しました。

Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; Microsoft; Lumia 950) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2486.0 Mobile Safari/537.36 Edge/13.10586

例えば以下のような条件判定に一致するようになります。

var ua = navigator.userAgent.toLowerCase(), cond;

cond = /android/.test(ua) && /mobile/.test(ua);
console.log("Android : " + cond); // "Android : true"

cond = /safari/.test(ua);
console.log("Safari : " + cond);  // "Safari : true"

Linux; U;が入っていないのが救いですね。
参照: 滅び行くAndroid 標準ブラウザをサポート外にして悩みの種をなくす話 - Qiita


User-Agentでブラウザの判断をせざるを得ない現状も個人的にはどうかと思います。
本当であれば機能面で分けるべきなんですよね。

console.log("Legacy IE : " + (/*@cc_on ! @*/false));

var webkitKeys = Object.keys(window).filter(function(e){
  return window.hasOwnProperty(e) && e.indexOf("webkit") !== -1;
});
console.log("WebKit : " + (webkitKeys.length > 0));

まぁこれはこれで穴がありますが…。

POH7の問題でSwiftを初めて書いた

Paizaさんは相変わらず変態ですね(褒め言葉
今回のPOHも例に漏れずぶっ飛んだ設定になっています。

さて、縞ニーソの問題(この文だけですでに病気だ…)ですが、始めは無難にRubyで書いていたのですが、POH7からはSwiftコンパイラも採用されたということでSwiftでも書いてみることにしました。
ちなみにgolfもやっていたようなので、なるべく短く書くようにしました。

Swiftについては今までそこかしこでObjective-Cとの対比で「短く書ける」と紹介されていたエントリをいくつか読んだ程度で、実際に書いたことはなく、また構文も特に勉強していなかったため全く書けない状態での挑戦です。
知っていることと言ったら

var s = "variable string" // var で変数宣言
let c = "const string"    // let で定数宣言

// func で関数宣言
func f() {
  // do something
}

くらいでした。

本題

前置きはこの程度にして、設問ですが、

赤と白の等間隔の縞模様をあなたは作ろうとしています。

各色の幅 n 、縞模様全体の長さ m が改行区切りで入力されます。
赤を 'R' 、白を 'W' とした赤から始まる縞模様を出力して下さい。

例えば
3
10
のような入力の場合
RRRWWWRRRW
のように出力してください。

というものです。

1回目

最初に書いたコードはこちらです。

// 98bytes
var n=Int(readLine()!)!,m=Int(readLine()!),i=0;for;i<m;++i{print(i/n&1==0 ?"R":"W",terminator:"")}

// 展開すると
var n = Int(readLine()!)!, m = Int(readLine()!)!
for var i = 0; i < m; ++i {
  print(i / n & 1 == 0 ? "R" : "W", terminator: "")
}

軽く解説しますと、readLine()が標準入力から1行読み取る関数で、返り値の型はString?です。
String?Optional<String>と同じ意味を表し、つまりOptional型の一つです。
Optional型は型引数に取る型の値以外にnilも持てる型です。
SwiftではOptional型を純粋な型に戻す時!を後ろに付けます。
そしてInt()はキャスト用の関数です。返り値の型はなぜかInt?です。
なのでvar n = Int(readLine()!)!は標準入力から一行読み取り、読み取った文字列を数字としてnに代入する、という操作になります。

i / n & 1 == 0の部分はi / nが奇数なのか偶数なのかの判断をしています。
素直に考えれば奇数か偶数かの判断はi / n % 2 == 0、つまり「2で割って余りが0になるかどうか」になるかと思いますが、なぜこれで奇数と偶数を判断できるのか。
&演算子はビット演算子と呼ばれるものの一つで、AND演算を表します。
細かい説明は省きますが、AND演算では与えられた二つの二進数の同じ桁を比較し、両方のビットが立っている時に1とします。

0000 & 0001 = 0000 // 0 & 1 = 0
0001 & 0001 = 0001 // 1 & 1 = 1
0010 & 0001 = 0000 // 2 & 1 = 0
0011 & 0001 = 0001 // 3 & 1 = 1
0100 & 0001 = 0000 // 4 & 1 = 0
0101 & 0001 = 0001 // 5 & 1 = 1
0110 & 0001 = 0000 // 6 & 1 = 0
......

…とまぁ、こういうわけです。
別にi / n % 2 == 0でも問題ないどころか可読性はこちらの方が高いのですが、ビット演算の方がより高速に処理できます*1

始めはn回ごとに'R'と'W'を切り替える処理をゴリゴリ書いていたのですが、

i = 0
s = "R"
m.times do
  if i == n then
    s = s == "R" ? "W" : "R"
    i = 0
  end
  print s
  i += 1
end

一度このコードで提出してから、整数型を整数型で割ると返ってくる値は小数点以下を切り捨てた整数であることに気づきました。
n回ごとに'R'と'W'が切り替わるのであれば、n*2回ごとに1周するはず。
つまり0からmまでのループ変数iを取るとき、i / nが奇数なのか偶数なのかで'R'を出力するのか'W'を出力するのかが一意に決まります。
そういうわけでここでは奇数偶数判定を用いています。

さて、残るは出力ですが、Swift 1.xでは標準出力用の関数としてprintprintlnの2つを用意し、printでは末尾に改行を入れず、printlnでは末尾に改行を入れる、という差を設けていたらしいです。
しかしSwift 2.0になった時にprintlnを廃止し、printに一本化したようです。
そして改行なしの出力をしたい場合は、第二引数のオプションにterminator: ""を付けろ、ということになったみたいです。

長かったけどこれで解説とします。全然軽くなかった。

2回目

二度目に提出したのが以下です。

// 88bytes
var n=Int(readLine()!)!,s="";(0..<Int(readLine()!)!).map{s+=$0/n&1==0 ?"R":"W"};print(s)

// 展開すると
var n = Int(readLine()!)!, m = Int(readLine()!)!, s = ""
(0..<m).map {
  s += $0 / n & 1 == 0 ? "R" : "W"
}
print(s)

基本的には変わってないのですが、Rangeを利用しています。

let m = 0, n = 10

// mからnまでの範囲を表す
let r1 = m...n
// mからnまで(nを含まない)の範囲を表す
let r2 = m..<n

var a1 = [Int](), a2 = [Int]()
for var i in r1 {
  a1.append(i)
}
for var i in r2 {
  a2.append(i)
}
print(a1) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(a2) // [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

ちなみにforEachメソッドだと長いのでmapメソッドを使っています。
ブロック内部ではただsへの再代入をしているだけなので返り値がなく、そのことについてコンパイラが警告を出してきますが、コードを短くするためには已む無しなので無視します。

最初はmapで'R'か'W'を持つ配列にして、最後にjoinしようと考えていたのですが、

let arr = ["a", "b", "c"]
print("".join(arr)) // "abc"

とできたのは、Swift 1.xの頃の話で、Swift 2.0からは

let arr = ["a", "b", "c"]
print(arr.joinWithSeparator("")) // "abc"

となってしまい、全然コード量の節約にならなかったため、泣く泣く文字列に追加する方式を取っています。

ちなみにmapメソッド内部に書かれた$0はブロックに渡される0番目の仮引数です。

let r = 0...10

let a1 = r.map{ i in i * 2 }
let a2 = r.map{ $0 * 2 }

このa1a2は同じ結果が入ります。

こんな感じでコードを短くしていたんですが、私の頭ではこれ以上無理でした。
ランキングでは71bytesが最短らしく、私よりも17bytesも短いです。
もう少し勉強してより短い糖衣構文をいろいろ習得する必要がありそうです。


ところでRubyでは最終的に以下のようなコードを書きました。

# 48bytes
n=gets.to_i;gets.to_i.times{|i|print"RW"[i/n&1]}

# 展開すると
n = gets.to_i
m = gets.to_i

m.times do |i|
  print "RW"[i / n & 1]
end

Rubyでは文字列に添え字をつけるとsliceメソッドと等価になります。

s = "abcdefghi"

p s[2..5]        # "cdef"
p s.slice(2..5)  # "cdef"

p s[1, 2]        # "bc"
p s.slice(1, 2)  # "bc"

1をAND演算すると結果が0か1のどちらかのみに絞られることについては上で説明した通りです。
なので"RW"という2文字の0番目、または1番目を取り出して出力、というコンパクトなコードになります。

【追記】一文字減らせた

# 47bytes
n=gets.to_i;gets.to_i.times{|i|print:RW[i/n&1]}

文字列型"RW"の代わりに、シンボル型:RWを使いました。

【さらに追記】さらに一文字減らせた

# 46bytes
n,m=$<.map(&:to_i);m.times{|i|print:RW[i/n&1]}

# パーレンを省略するとさらに一文字
# 45bytes
n,m=$<.map &:to_i;m.times{|i|print:RW[i/n&1]}

Rubyの特殊変数$<を使っています。
これはARGFエイリアスで、こいつにEnumerableのメソッドを付けてやると標準入力を行ごとに取ってくるらしいです(よく理解していない)
参照: AtCoderで見かけたRubyショートコーディング術 - Qiita

あと、縞ニーソ問題のSwiftの最短コード数が69bytesになってますね(12月18日23時前現在)。変態どもめ…。

試してみたい方へ

Swiftはここで書いて遊べます。Xcode持ってるならそちらでもいいけど。
SwiftStub: Online Swift Compiler

Rubyはこちらがお勧めです。別にIdeoneでもいいんですが、こちらの方が手軽です。
compile ruby online

*1:コンパイラの最適化具合にもよります

月末ギリギリでのmineoへのMNPはやめた方がいい

mineoではMNP転入の手続きは、消費者自身がmineoマイページの所定のフォームにSIMの製造番号の下4桁を入力して完了となります。
その為、必然的にSIMが届くまではMNPを完了させることができません。
mineoで申し込みをしてから受理されるまで1~2日、さらにSIMが発送されてから届くまで2~3日かかります。

申し込んだ後にこのことに気づいて慌ててmineoサポートセンターに問い合わせても、サポートからは倉庫と連絡を取り合う手段がないため、届く前のSIMの製造番号は確認できません。
また申し込みのキャンセルもできず、SIMの受け取り拒否をしたとしても申し込みから15日後には強制的に切り替わってしまいます。

つまり月末に申し込んだ時点で、MNP元の更新月であったとしてもほぼ確実に解約違約金の10260円がかかることが確定します。
IIJmioでは申し込んだ時点で業者側が勝手に切り替えてくれていたので油断していました。*1

今回は勉強代としておとなしく支払うことにします。
くれぐれもMNPは余裕を持って行うように心がけたいです。

*1:現在ではIIJmioもmineoと同じくユーザー側で切り替える方法になっているようです。