技術とか戦略とか

IT技術者が技術や戦略について書くブログです。

java:絵文字を含む文字列を1文字ずつ切り出す

🗿←こんな感じの絵文字を資料中に使うのが今の職場で流行ってます。

そういえば実務で絵文字を取り扱うシステムに携わったことがなかったので、興味本位で調べてみました。

ついでに、絵文字を含む文字列を1文字ずつ切り出すjavaのサンプルコードも作りました。

 

【絵文字の定義】

絵文字は符号化文字集合Unicode」で定義されており、Unicode文字符号化方式である「UTF-8」「UTF-16」等で使用することができる。

(「符号化文字集合」とは「文字」と「文字に割り当てた番号」の対応表、「文字符号化方式」とは「文字に割り当てた番号」と「実際にコンピュータが扱う数字」の対応表のことである)

なお、「UFT-16」は狭義の「Unicode」として呼ばれることもある。

 

Unicodeは元々1~2バイト文字を定義していたが、世界中の文字を取り扱いたいという要望に応えるために4バイト文字を拡張領域として定義した。

絵文字は、この拡張領域に含まれる。

4バイト文字は、「上位サロゲート(2バイト)+下位サロゲート(2文字)」の組み合わせで定義される。

「上位サロゲート」は0xD800~0xDBFF(1024通り)、「下位サロゲート」は0xDC00~0xDFFF(1024通り)で定義され、何れも2バイト文字では使用しないコードであるため、表現が衝突することはない。

 

4バイト文字は定義当時は実際に扱われることが少なかったが、日本の携帯の絵文字の普及により一般的に使われるようになり、Webシステム等では無視できない存在となった。

 

【サンプルコード】

・コード

public class Sample {

  public static void main(String args[]){

    // 引数から「🚅Unicode🌏絵文字で遊んでみよう😮」を取得し表示→化ける

    System.out.println("引数から取得:"+args[0]);

    // 変数で直接4バイト文字込みの文字列を定義し表示→化けない

    String str = "🚅Unicode🌏絵文字で遊んでみよう😮";

    System.out.println("変数から取得:"+str);

    // 何も考えず1文字ごと文字と文字コードを出力→4バイト文字は2文字扱い

    for (int i = 0; i < str.length() ; i++) {

      int code = (int)str.charAt(i);

      String hex = Integer.toHexString(code);

      System.out.println((i + 1) + "番目の文字:" + str.charAt(i) + " 16進数:" + hex);

    }

    // サロゲート文字で4バイト文字を判定し、正しく1文字ずつ切り出す

    String upperSurStart = "d800";

    String upperSurEnd = "dbff";

    int fourByteMojiCount = 0;

    for (int i = 0; i < str.length() ; i++) {

      int mojiPos = i+1-fourByteMojiCount;

      int code = (int)str.charAt(i);

      String hex = Integer.toHexString(code);

      String strOneMoji = "";

      if (hex.compareTo(upperSurStart)>=0 && hex.compareTo(upperSurEnd)<=0) {

        strOneMoji = str.substring(i,i+2);

        i++;

        fourByteMojiCount++;

      } else {

        strOneMoji = str.substring(i,i+1);

      }

      System.out.println(mojiPos + "番目の文字:" + strOneMoji);

    }

  }

}

 

・出力

引数から取得:??Unicode??絵文字で遊んでみよう??

変数から取得:🚅Unicode🌏絵文字で遊んでみよう😮

1番目の文字:? 16進数:d83d

2番目の文字:? 16進数:de85

3番目の文字:U 16進数:55

4番目の文字:n 16進数:6e

5番目の文字:i 16進数:69

6番目の文字:c 16進数:63

7番目の文字:o 16進数:6f

8番目の文字:d 16進数:64

9番目の文字:e 16進数:65

10番目の文字:? 16進数:d83c

11番目の文字:? 16進数:df0f

12番目の文字:絵 16進数:7d75

13番目の文字:文 16進数:6587

14番目の文字:字 16進数:5b57

15番目の文字:で 16進数:3067

16番目の文字:遊 16進数:904a

17番目の文字:ん 16進数:3093

18番目の文字:で 16進数:3067

19番目の文字:み 16進数:307f

20番目の文字:よ 16進数:3088

21番目の文字:う 16進数:3046

22番目の文字:? 16進数:d83d

23番目の文字:? 16進数:de2e

1番目の文字:🚅

2番目の文字:U

3番目の文字:n

4番目の文字:i

5番目の文字:c

6番目の文字:o

7番目の文字:d

8番目の文字:e

9番目の文字:🌏

10番目の文字:絵

11番目の文字:文

12番目の文字:字

13番目の文字:で

14番目の文字:遊

15番目の文字:ん

16番目の文字:で

17番目の文字:み

18番目の文字:よ

19番目の文字:う

20番目の文字:😮

 

・余談

引数から文字列を与えた時は4バイト文字が「??」に化けた。

引数はUnicodeではないのだろうか?

(実務ではフォームやファイルが入力となり、そこで文字コードの指定ができるので、別に気にする必要はないのだが…)

 

【その他(MySQLについて)】

MySQLは5.5.3以降でないと4バイト文字を取り扱えない。

 (5.5.3以降では「utf8mb4」という文字コードで取り扱える)

--------------------------

追記

ソースコードを書くことが多くなってきたので、PC版のデザインを横幅なものに変更しました。

Excelでモンテカルロシミュレーションを試してみた

Excelでごく簡単なモンテカルロシミュレーションを試してみる記事です。
 
モンテカルロシミュレーションとは、ランダムな試行を繰り返すことで解に近い結果を導き出すもので、複雑で解を出すのが困難な問題に対して適用すると比較的短時間で解に近い結果を得ることができます。
簡単な問題に対してはExcelで十分対応できます。
 
例題として、以下の問題をモンテカルロシミュレーションで解いてみます。
妥当性を確認するため、あえて容易に解を出せる問題にしています。
 
【例題】
ドラゴンに対する勇者の攻撃は80%の確率で命中し、ダメージは90~99の間の整数値を取り、ドラゴンのHPが95である場合、ドラゴンを倒せる確率(HPを0以下にできる確率)は何%か?
 
【正解】
攻撃によるダメージが95~99の時にドラゴンを倒すことができる。攻撃が命中すると仮定した場合、95~99のダメージが出る確率は50%である。
よって、80%×50%=40%(0.4)の確率でドラゴンを倒すことができる。
 
モンテカルロシミュレーションの実装】
rand関数により乱数を発生させ、1000回シミュレーションを行う。

https://cdn-ak.f.st-hatena.com/images/fotolife/a/akira2kun/20180809/20180809233936.jpg?1533825594

A3の式…=IF(INT(RAND()*10)<8,"命中","外れ")
B3の式…=IF(A3="命中",90+INT(RAND()*10),0)
C3の式…=IF(B3>94,"倒せる","倒せない")
A3~C3はA1002~C1002までコピペ
D3の式…=COUNTIF(C3:C1002,"倒せる")/COUNTA(C3:C1002)
 
D3に出力される値がモンテカルロシミュレーションの結果となる。
 
モンテカルロシミュレーションの結果】
上記の画像では0.411であり、回答の0.4に近い結果を得られたが誤差があることがわかる。
なお、F9キーを押して何度も再計算すると0.4より小さい値になることもあることが確認できる。
今回は1000回の試行のため誤差が大きくなっているが、試行回数を増やせば精度が高まることが予想される。
-----------------------
なお、再帰的な計算が必要になる、DBにアクセスする必要がある等、複雑なケースの場合はスクリプト言語やプログラム言語を用いる必要があります。
私は趣味でモンテカルロシミュレーションを3回適用したことがありますが、Excelで済んだのは1回だけでした。

ExcelでINSERT文を作成

Excelを使ってSQLのINSERT文を作成してみる記事です。

Excelの機能を使うことで、効率良く大量のINSERT文やUPDATE文等を作成できます。

臨時の運用対応ではデータが公表されてから30分以内にDBに反映させなければならない等、限られた時間でのデータ補正が必要になるため、プログラムを事前に用意できない場合はExcelでの対応が有効になります。

運用対応だけでなく、開発時のテストデータ作成も効率的に行うことができます。

 

以下は例となります。

 

【INSERT対象のテーブル定義】

create table 商品(

商品ID INT PRIMARY KEY,

商品名 CHAR(30),

登録年月日時分秒 CHAR(14)

);

 

【INSERT文の作成】

①下記のように入力する。

f:id:akira2kun:20180808224159j:plain

G2セルについては、下記の式を入力する。

=A$2&"000000"

この式によりA2セルと文字列"000000"を結合する。

参照時には$マークをつけて絶対参照とする。

(後の手順でコピーする時に参照先がずれないようにするため)

 

②B2~H2セルを3~6行目にコピーする。

f:id:akira2kun:20180808224225j:plain

 

③C3セルに2を入力してから、C2~C3セルを選択し、4~6行目までオートフィルする。

f:id:akira2kun:20180808224236j:plain

 

④B2~H6セルをコピーし、Sakuraエディタ等のテキストエディタに張り付ける。

 

⑤セルを区切るtabを削除する。

 

【完成したINSERT文】

INSERT INTO 商品 VALUES(1,'hoge                          ',20180808000000);

INSERT INTO 商品 VALUES(2,'hoge                          ',20180808000000);

INSERT INTO 商品 VALUES(3,'hoge                          ',20180808000000);

INSERT INTO 商品 VALUES(4,'hoge                          ',20180808000000);

INSERT INTO 商品 VALUES(5,'hoge                          ',20180808000000);

--------------------

なお、今回紹介していない機能としては、区切り位置、重複の排除、並び替えとフィルタ等を良く使います。

これらの機能を使えばフォーマット変換やデータ抽出等も可能になります。

行動経済学の用語を1行ずつまとめる記事

行動経済学とは、人間の合理的ではない判断を研究する学問です。
人間の行動を予測したり、人間の癖を把握して合理的な判断をしたりするために広く使われる学問です。
今回の記事では、行動経済学の用語(概念、知見)を厳選し、1行ずつまとめます。
どのような用語があるのか知りたい場合や、行動経済学の知識を整理したい場合にお使いください。
※人間の合理的ではない判断を一覧にするのが当記事の目的なので、心理学の用語と思われる用語もこっそり混ぜています。ご了承ください。
※挙げ忘れた用語があれば、後に別の記事で補足するかもしれません。
 

  • プロスペクト理論(価値関数)
    ある基準点を下回る損失は、その基準点を上回る利得の2倍感じやすい。
  • プロスペクト理論(確率加重関数)
    0.0 < p < 0.4 の確率は過大評価し、 0.4 < p < 1.0 の確率は過小評価する。
  • 曖昧性忌避
    結果の確率が不明の場合、人々は曖昧さを嫌ってその曖昧な選択肢の選択を避ける。
  • アンカリング
    先に提示された数値を基準として行動判断してしまう。
  • 確証ヒューリスティック
    自分にとって都合の良い情報を集めて行動判断しようとする。
  • 利用可能性ヒューリスティック
    記憶に残りやすい情報について、頻度や確率を高く見積もる。
  • 代表性ヒューリスティック
    ある本質を代表するに過ぎない情報を用いて、頻度や確率を高く見積もる。
  • サンクコスト
    過去に払ってしまったコストを現在の行動判断に反映させてしまう。
  • 希少性の原理
    後悔を避けるため、数が少なかったり期間が限定されていたりするものに高い価値を感じる。
  • 心の会計
    お金の入手方法や用途によって、同じ金額のお金であっても価値が異なるものかのように感じる。
  • 双極割引
    評価する時点が遠ければ忍耐できるが、評価する時点が近ければせっかちになる。
  • 自信過剰バイアス
    人間は基本的に自信過剰であり、少しの知識や経験で自分の力量を過信する。
  • 学習性無力感
    行動しても状況を変えられない経験をすると、行動することで状況を変えられる場合においても行動しても無駄だと感じてしまう。
  • 認知的不協和
    自分の信念と矛盾する新たな事実を認識し不快感を覚え、信念を変えることが困難な場合、新たな事実を否定して不快感を解消しようとする。
  • 初頭効果
    最初の印象で物事の判断に大きく影響する。
  • ピークエンドの法則
    経験の快楽・苦痛の記憶はピーク時と終了時の快楽・苦痛の度合いで決まる。
  • 選択肢過多
    選択肢が多すぎると選択すること自体が困難になり、満足度が下がる。
  • バンドワゴン効果
    大勢の人から評価されている物事に、自分も好印象を抱いてしまう。
  • ハロー効果
    ある対象を評価するときに、その評価とは全く関係のない特徴や印象に引っ張られて評価が上下してしまう。
  • 集団浅慮
    集団で意思決定した場合、意見に多様性が無くなり極端な意思決定をしてしまう。
  • 内集団バイアス
    自分が所属している集団には好意的な態度をとり、外の集団には差別的な態度をとる。
  • 社会的手抜き
    集団になると個々の成員は人頼みになり全力を出さなくなる。

C言語:NUL文字を含むファイルを1レコードずつ読み込む

ググっても出てこなかったのでメモ。
 
C言語でファイルを1レコード読む場合は、通常はfgetsを使用します。
しかし、fgetsで読み込んだレコードにNUL文字(\0)が含まれる場合、読みこんだ文字列がNUL終端されてしまい、NUL文字以降改行コードまでの文字列を取得できなくなってしまいます。
NUL文字以降の文字列を取得したい場合は、fgetcで1文字ずつ読み込み、NUL文字や改行コードを読みこんだ際の処理を自力で実装する必要があります。
Linuxのコマンド等でNUL文字を他の文字に置換し中間ファイルに出力し、その中間ファイルをfgetsで読み込んでも良いのですが、余分なファイルIOが発生するので性能がシビアな要件では避けたい実装です)
 
以下、サンプルコードです。
NUL文字を含むファイルを1レコードずつ読み込み、レコードフォーマットを編集してファイルに出力する処理です。
 
【サンプルコード】
#include <stdio.h>
#include <stdlib.h>
 
#define N 1024
 
/* main */
int main(void) {
    FILE *fp1;
    FILE *fp2;
    char *filename1 = "/home/hoge/in.txt";
    char *filename2 = "/home/hoge/out.txt";
    char readline[N] = {'\0'};
    int ch;
    int i;
 
    /* 初期化 */ 
    memset(readline, '\0', sizeof(readline));
    i=0;
 
    /* ファイルのオープン */
    if ( (fp1 = fopen(filename1, "rb")) == NULL) {
        fprintf(stderr, "%sのオープンに失敗しました.\n", filename1);
        return 1;
    }
    if ( (fp2 = fopen(filename2, "wb")) == NULL) {
        fprintf(stderr, "%sのオープンに失敗しました.\n", filename2);
        return 1;
    }
 
    /* ファイルの終端まで文字を1文字ずつ読み取り出力する */
    while ( (ch = fgetc(fp1)) != EOF ) {
        /* NUL文字を変換(後の処理でNUL終端されるのを避ける) */
        if (ch==0){ //NUL文字
            ch=44;  //カンマ
        }
        /* 1文字ずつ文字列に書き込み */
        readline[i]=(char)ch;
        i++;
        /* 1レコード読みこんだ場合 */
        if (ch==10){ //改行コード(\n)
            /* 実際はここでレコードフォーマット編集 */
            /* 編集した文字列をファイル出力 */
            fprintf(fp2, "%s",readline);
            /* 次のレコード読み取りに備え初期化 */
            memset(readline, '\0', sizeof(readline));
            i=0;
        }
    }
 
    /* ファイルのクローズ */
    fclose(fp1);
    fclose(fp2);
 
    return 0;
}

利得を代表する評価値の選定方法

ゲーム理論で分析する際、利得をどのように数値化するかが問題となります。
「勝率」や「金額」といった、数値化された絶対的な基準で利得を求めるのが理想ですが、ごく簡単な状況でない限りこのような形で正確に利得を求めることはできず、多くの場合は主観で「だいたいこれぐらいの勝率」「だいたいこれぐらいの金額」といった形で決めることになります。
しかし、これでは心理的なバイアスの影響を受ける可能性がありますし、人間の代わりにプログラムで利得を求めることもできなくなります。
 
そこで、利得を代表する評価値を選定し、その評価値を利得として扱うという手段が有効になります。
評価値は、ゲームのルールを分析し、そのルールから各プレイヤーが取る行動を導き出し、その行動の良し悪しを代表する指標を見つけることで、選定することができます。
 
ポケモン対戦を例に挙げて、評価値の選定方法を具体的に見ていきます。
 
何も知らない人向けにポケモン対戦のルールをざっくり説明すると、以下の通りになります。

  • 2人のプレイヤーが勝敗を競うゲームである
  • お互いに同時に意思決定を行うゲーム(同時進行ゲーム)である
  • お互い3匹ずつのポケモンを所持し、一度に1匹のポケモンを場に出せる
  • 各々のポケモンには相性関係があり、基本的にはじゃんけんで言うグー・チョキ・パーに該当するポケモンをお互いに持つ
  • 1ターンの中で攻撃か交代を選択することができ、交代は攻撃よりも先に行われる
  • 攻撃すると相手のポケモンのHPを減らすことができ、HPが0になるとそのポケモンは使えなくなる
  • 全てのポケモンのHPが0になると負けとなる
  • 相性関係で有利なポケモン(例:グーに対するパー)の攻撃はHPを大きく削ることができ、相性関係で不利なポケモン(例:グーに対するチョキ)の攻撃はHPをあまり削ることができない

このルール下では、相性関係で有利なポケモンに攻撃されるのを防ぐのが肝要になります。
よって、以下のような行動が定石となります。

  • 相手のポケモンに対して相性関係で有利(もしくは互角)な場合は攻撃する(例:相手がグー、自分がパーの場合は攻撃する)
  • 相手のポケモンに対して相性関係で不利(もしくは互角)な場合は、相性関係で有利なポケモンに交代する(例:相手がグー、自分がチョキの場合は、パーに交代する)
     

しかし、相性関係で有利なポケモンで相手のポケモンの攻撃を受けるとしても、何回か交代で出している内にHPはじわじわと削れていき、最終的にはHPが0になり倒れてしまいます。
先にHPが0のポケモンを出してしまうとその後の展開は非常に不利になり、大抵の場合は敗北します。
つまり、「交代で出せる回数」を相手よりも多く確保することが重要となります。
この「交代で出せる回数」は交代を繰り返すポケモンの対戦で有利・不利を決定づける重要な指標となり、また勝率よりもかなり容易に算出できることから、評価値として適している指標となります。
 
なお、参考文献は以下となります。ポケモン対戦の専門的な文献です。
今回の記事はポケモン対戦を知らなくてもイメージできるように書いていますが、ポケモン対戦を経験した方ならこちらの文章の方が正確に理解できます。

 

・徒然なる雑記 - 役割解析
 http://vento.blog3.fc2.com/blog-entry-127.html

情報処理技術者試験対策「SQL(制約関連の細かい文法)」

今回の記事では、実務ではなかなか見ることがないが情報処理技術者試験では出る可能性がある制約関連の文法を紹介したいと思います。
 
実務で良く見る制約としては、一意でなければならずNULL値も許可しない主キー制約(PRIMARY KEY制約)、値が一意でなければならない一意キー制約(UNIQUE制約)、NULL値を許可しないNOT NULL制約、過去の記事で紹介した外部キー制約(FOREIGN KEY制約)といった定義が存在します。
しかし、他にもデフォルト値や検査制約といった制約が存在するので、今回の記事で紹介します。
また、制約に関連する文法として、制約名付与、ドメイン作成、表明作成といった文法も存在するので、それも今回の記事で紹介します。
なお、ドメイン作成と表明作成はSQL92で標準化された比較的新しい文法なので、DBMS製品によってはそもそも実装されていない可能性があります。
(特に表明は超マイナーです。にも関わらずDBスペシャリストでは出題実績があります…。)
 
【その他の制約】

  • デフォルト値(DEFAULT制約)
    INSERT文でレコードを挿入する際、項目を指定しなかった場合は通常NULLが設定されるが、デフォルト値を設定しておくとそのデフォルト値が適用される。
    (文法(列制約の場合))
    カラム名 型 DEFAULT デフォルト値
    (例)
    create table 商品(
    商品ID INT PRIMARY KEY,
    商品名 CHAR(50) DEFAULT 'hoge'
    );

    INSERT INTO 商品(商品ID) VALUES(1);
    で、商品名に'hoge'が設定される。
  • 検査制約(CHECK制約)
    INSERT文やUPDATE文でカラムに値をセットする際、カラムにセット可能な値を指定し、その指定の範囲外の値をセットしようとした際に処理を失敗させる。
    (文法(列制約の場合))
    カラム名 型 CHECK (セット可能な値を示す式)
    (例)
    create table 商品(
    商品ID INT PRIMARY KEY,
    商品名 CHAR(50),
    重量 INT CHECK(重量>0)
    );

    INSERT文やUPDATE文で重量に0以下の値をセットしようとすると失敗する。
     

【制約に関連する文法】

  • 制約名付与(CONSTRAINT句)
    制約に任意の名前を付けることができる。
    制約に名前を付けておくと、ALTER TABLEで制約を削除する際に、名前を指定して削除することも可能になる。
    (文法(列制約の場合))
    カラム名 型 CONSTRAINT 制約名 制約の記述
    (例)
    create table 商品(
    商品ID INT PRIMARY KEY,
    商品名 CHAR(50) CONSTRAINT 商品非NULL NOT NULL
    );

    ALTER TABLE 商品 DROP CONSTRAINT 商品非NULL;
    で制約削除ができる。
    ※制約名を指定しなくても「ALTER TABLE 商品 MODIFY (商品名 NULL);」で制約削除できる。
  • ドメイン作成(CREATE DOMAIN)
    独自にドメイン(INTやCHAR等と同じ扱いの型)を定義できる。
    (文法)
    CREATE DOMAIN ドメイン名 型の内容
    (例)
    CREATE DOMAIN 名前 CHAR(50)
    create table 商品(
    商品ID INT PRIMARY KEY,
    商品名 名前
    );

    商品名の型がCHAR(50)でテーブルが生成される。
  • 表明作成(CREATE ASSERTION)
    複数のテーブルに対して制約をかけることができる。
    (文法)
    CREATE ASSERTION 表明名 CHECK(セット可能な値を示す式)
    (例)
    create table 商品(
    商品ID INT PRIMARY KEY,
    商品名 CHAR(50),
    価格 INT
    );
    create table 価格下限(
    商品ID INT PRIMARY KEY,
    価格下限 INT
    );
    CREATE ASSERTION 価格チェック CHECK
    (NOT EXIST
     (SELECT *
      FROM 商品
      JOIN 価格下限
      ON (商品.商品ID=価格下限.商品ID)
      WHERE 商品.価格 < 価格下限.価格下限
     )
    )

    価格下限を下回る価格の商品が登録されることがないかを検査している。
    例えば、価格が80、価格下限が100の商品を商品テーブルに登録しようとするとエラーになる。

---------------------
目次

https://1drv.ms/b/s!AivF3bzWXOzuhG1Xk5hscKYqkLkM

 
ネタに困った時はSQLネタが良いですね。
よほど古いシステムかよほど新しいシステムでもない限りSQLはどこでも使いますし、私自身も扱いに慣れているので。