B-Teck!

お仕事からゲームまで幅広く

【JavaScript】配列の要素の入れ替え

配列の要素の順番を入れ替えるとき、

let temp = ary[x];
ary[x] = ary[y];
ary[y] = temp;

みたいにやってたけど、
なんか1行でできるらしい。

function swap(a,x,y){
  a[x]=[a[y],a[y]=a[x]][0];
  return a;
}

最初見たとき意味わかんなかったんだけど、コメント追加して書き下すとこう。

function swap(array,index1,index2){
  // array[y]の値を添え字0に、
  // array[y]=array[index1]の「代入の実行結果」を添字1に持った配列を作成
  let array2 = [array[index2],array[index2]=array[index1]];
  
  // 上記の配列の添字0をarray[index1]に代入することで、
  // 引数の配列の入れ替えが完了する
  array[x] = array2[0];
  
  return array;
}

let ary = [9,8,7,6,5,4,3,2,1];
console.log(swap(ary,8,3));

言われてみりゃなるほどなって感じ。

【JavaScript】ArrayLikeObjectをArrayに変換する

ArrayLikeObjctとは

document.querySelectorAll()とかで戻り値になっているNodeListとかの型。
通常の配列のようにlengthとかを持っていたり、添字を使って各要素にアクセスできる。
でもArrayではないので、Arrayのメソッドとかは使えない。

そのままでは扱いづらいのでArrayに変換する方法のメモ。

// ES6以降が利用可能な環境であればこれでOKなはず。
// 一番シンプル
Array.from( arrayLikeObject ); 

// Array.fromが使えない環境用のpolyfill
if (!Array.from) {
    try {
        Array.prototype.slice.call( document.getElementsByTagName("html") );
        Array.from = function( arrayLikeObject ) {
            return Array.prototype.slice.call( arrayLikeObject );
        };
    } catch (err) {
        // Array.prototype.slice.call( ArrayLike ) でエラーになる場合は Array.apply を使う
        Array.from = function( arrayLikeObject ) {
            return Array.apply( null, arrayLikeObject );
        };
    }
}

// IE6〜IE8では使えない事もある
Array.prototype.slice.call( arrayLikeObject ); 
[].slice.call( arrayLikeObject ); 

// クロスブラウザらしい。わりと低速
Array.apply( null, arrayLikeObject ); 

// そこそこ高速だけれど、記述が冗長
var ary = []; 
for (var i = 0, iz = arrayLikeObject.length; i < iz; ++i) { 
    ary.push( arrayLikeObject[i] );
}

1年。

母親が死んで、1年が経った。
去年の今日は、普通にお祭りに行っていて、普通に遊んで帰って。
しかも週末を挟んで月曜日に会社に行って、
その帰り道に初めてそれを知ったんだったか。

生前の母は、割とすぐ生と死を持ち出すニンゲンだったので、
連絡が入ったときはまた何かの冗談か嘘かと思ったのを覚えている。

それからしばらくは夢に母が出てきたり、情緒が安定しなかったり、
仕事に集中できなかったり、しんどい時期が続いた。
なんとか毎日を生きているうちに、段々記憶が薄れてきて、
気がついたらもう1年。
半分忘れているような状態になっているのは、俺が薄情なのかしら。
でも、こんな記事を書いているうちは忘れられてないんだろうな。

この1年を思い返せば色々あって、
母が遺していった犬が引き取ってくれた親戚の元で死んでしまったり、
一緒に選んだアパートを引き払って新しい部屋に引越したり、
付き合っていた彼女と結婚したり。

こうやって、少しずつ薄れて、新しいことが起きて、体験して、
そうして死んでいくのかなと思うと少し怖いなぁ。

どうしてもこの時期は少し気持ちが安定しなくて、
仕事に集中できなかったり、気分の浮き沈みが激しくなってしまうけど、
年を経るごとにもうちょいマシになればいいなと思った。

【雑記】勉強

この前の日曜日、もう一度読む山川世界史という本を読み終わった。
いつだったかは失念してしまったけど、確か去年の暮れの頃に購入して、
半年以上かけてゆったり読んできた。

不思議なもので、ここ最近は勉強が楽しくて、
語学学習アプリのDuolingoを使って英語とドイツ語の勉強を少しずつ進めている。
世界史は、大まかな流れを知れたので細かく知っていこうと、
世界史用語集片手に書き込み教科書 山川世界史を読み始めた。

元々、学生時代から勤勉さとは無縁で、テスト前の一夜漬けや、
たまたまサボっていない授業中以外はあまり好んで勉強をするタイプではなかった。
それがどうして、今はゆっくりとだけれど、楽しく勉強している。

勉強のきっかけは、実は以前にも記事にしたバトルフィールド1だ。
この作品のキャンペーンモード(1人用のストーリーモード)や、 史実の戦闘を再現したオペレーションモードなどをプレイして、
戦闘の経緯や、第一次大戦の前史を調べているうちに気がついたら世界史全体に及んでいた。 ついでに、プレイヤーの操作するキャラクターが喋る言語(特に英語やドイツ語)に興味が湧き、
自然とそれらに関心が向いていた。 始まりがゲームというのは実に自分らしいのかもしれない。

勉強をしはじめて、幾度か学生のときにもっとちゃんと勉強していればなぁと思ったものだけれど、
おそらく、今だからこそ楽しいのだろうなぁとも思う。
学生を経て、社会人になり、世間や世界を見て、今の自分の目を通して見ているものは、
漫然と学生をしていた頃の自分には見えなかったものなんだと思う。

何かを知って、学ぶ度、新しく知りたいことや、学びたいことがまた増えて、
どこまで行っても果てが無く感じるけれども、自分の人生に果てはあって。
残りの人生でどれだけのことが識れるのかなぁと思った。

【JavaScript】日付の妥当性をチェックする

正規表現でチェックして欲しい形式以外をふるいにかけた後、
Date型に突っ込んで突っ込む前と同じ年月日かを確認する。

これで欲しい形式以外は入ってこないし、変な日付が入ってきて無理やり変換されても
変換前との比較で判定できる。

別の形式も許容する場合は、isNaN()とか入れる必要があると思う。

function isDate(strDate){
    // 空文字は無視
    if(strDate == ""){
        return true;
    }  
    // 年/月/日の形式のみ許容する
    if(!strDate.match(/^\d{4}\/\d{1,2}\/\d{1,2}$/)){
        return false;
    } 

    // 日付変換された日付が入力値と同じ事を確認
    // new Date()の引数に不正な日付が入力された場合、相当する日付に変換されてしまうため
    // 
    var date = new Date(strDate);  
    if(date.getFullYear() !=  strDate.split("/")[0] 
        || date.getMonth() != strDate.split("/")[1] - 1 
        || date.getDate() != strDate.split("/")[2]
    ){
        return false;
    }

    return true;
}

console.log(isDate(""));               //true 空文字は許容
console.log(isDate("2016/01/01"));     //true
console.log(isDate("2017/02/28"));     //true
console.log(isDate("2017/2/02"));      //true
console.log(isDate("2017/12/2"));      //true
console.log(isDate("20160101"));       //false
console.log(isDate("2016-01-01"));     //false
console.log(isDate("2016/01/01/"));    //false
console.log(isDate("2017/02/29"));     //false
console.log(isDate("2017/22/29"));     //false

【Java】半角カナ判定

正規表現

  • U+FF65「・」(半角カナ中黒)~U+FF9F「゚」(半角半濁点)の範囲で判定する。

細かい各メソッドの挙動とかは下記を参照。
https://docs.oracle.com/javase/jp/8/docs/api/java/util/regex/Pattern.html
https://docs.oracle.com/javase/jp/8/docs/api/java/util/regex/Matcher.html

    /**
     * 半角カナチェック
     * 半角カナ以外を含む文字列の場合false
     * 
     * @param String value 判定対象文字列
     * @return boolean true:半角カナ、false:半角カナ以外
     */
    public static boolean isHankakuKana(String value) {
        return    java.util.regex.Pattern
                        .compile("^[\\uFF65-\\uFF9F]+$")
                        // "-"(半角ハイフン)をOKにしたい場合は下記
                        // .compile("^[\\uFF65-\\uFF9F\\s-]+$")
                        .matcher(value)
                        .matches();
    }
    
    //       java.util.regex.Pattern
    //       java.util.regex.Matcher
    //       の2つをimportした状態で下記の処理を行う場合と同等
    //
    //        Pattern pattern = Pattern.compile("^[\\uFF65-\\uFF9F\\s-]+$");
    //        Matcher matcher = pattern.matcher(value);
    //        return matcher.matches();

【JavaScript】半角の文字を判定する

正規表現

半角文字列の判定として「/[^\x01-\x7E]/」を使う。
[]の中に含まれる先頭のキャレット^は否定の意なので、
この場合はASCIIコードの「x01x7Eの範囲外の文字列」という意味になる。 これだけではカナは含まれないため、同様に「/[^\uFF65-\uFF9F]/」。
これはUTF-16の「半角中黒(FF65)~半濁点(FF9F)の範囲外の文字列」となる。

String.prototype.match

String.prototype.matchは文字列から正規表現にマッチングした文字を配列で返す関数で、
マッチングするものが無ければnullを返す。
value.match(/[\uFF65-\uFF9F]/gi)のようにgフラグ(グローバルフラグ)をつければ
マッチングした文字全てを配列として返すが、
デフォルトでは最初にマッチングした文字のみを返却する。

つまり、「全角の文字」が入力文字列に含まれていた場合は要素のある配列が返され、
!で評価を反転させることでfalseとなる。
逆に、「半角の文字」が含まれていた場合match()はnullを返すので、
!で評価を反転させることでtrueとなる。

function isHankaku(value){
    return !value.match(/[^\x01-\x7E]/) || !value.match(/[^\uFF65-\uFF9F]/);
}
function isHankakuKana(value){
    return !value.match(/[^\uFF65-\uFF9F]/);
}

console.log("---------------------------------------------");
console.log("isHankaku     : ");
console.log("あ            : " + isHankaku("あ"));
console.log("-             : " + isHankaku("-"));
console.log("ア             : " + isHankaku("ア"));
console.log("A             : " + isHankaku("A"));
console.log("あいうえオ     : " + isHankaku("あいうえオ"));
console.log("アイウエオ         : " + isHankaku("アイウエオ"));
console.log("---------------------------------------------");
console.log("isHankakuKana : ");
console.log("あ            : " + isHankakuKana("あ"));
console.log("-             : " + isHankakuKana("-"));
console.log("ア             : " + isHankakuKana("ア"));
console.log("A             : " + isHankakuKana("A"));
console.log("あいうえオ     : " + isHankakuKana("あいうえオ"));
console.log("アイウエオ         : " + isHankakuKana("アイウエオ"));
console.log("---------------------------------------------");

// 結果
//---------------------------------------------  
//isHankaku     :   
//あ            : false  
//-             : true  
//ア             : true  
//A             : true  
//あいうえオ     : false  
//アイウエオ         : true  
//---------------------------------------------  
//isHankakuKana :   
//あ            : false  
//-             : false  
//ア             : true  
//A             : false  
//あいうえオ     : false  
//アイウエオ         : true  
//---------------------------------------------