2014年11月27日木曜日

Rでオブジェクトの存在を確認する方法

Rでは変数名の上書きをうっかりしないよう、プログラマは変数を意識してコードを書かなければならない。そこで、Rにおいてオブジェクトが既に存在しているか確認する方法についていくつか挙げてみる。

  1. ls()関数
    • オブジェクトの一覧を表示する関数である。search()関数を利用するとサーチパス上にある名前空間の一覧をすべて見ることができる。
      > search()
      [1] ".GlobalEnv"        "package:stats"     "package:graphics" 
      [4] "package:grDevices" "package:utils"     "package:datasets" 
      [7] "package:methods"   "Autoloads"         "package:base" 
      

      単にls()とすると、".GlobalEnv"の中にあるオブジェクト一覧が表示される。

      > a < -5
      > ls()
      [1] "a"
      
      他の名前空間にあるオブジェクト一覧を知りたいというときは、search()関数で分かった順番を基に、pos引数を使って指定すればよい。以下の例では、2番目の値にあったstatsパッケージのオブジェクト一覧を見ていることになる。
      > head(ls(pos=2))
      [1] "acf"        "acf2AR"     "add.scope"  "add1"       "addmargins"
      [6] "aggregate" 
      
  2. exists()関数
    • オブジェクトの存在をダイレクトに確認するのであれば、この関数を利用するとよい。

2014年10月31日金曜日

PHPにおける文字のエスケープ処理

magic_quotes_gpcというオプションがphp.iniにある。このオプションが有効になっていると、データを渡していくことを繰り返すうちに文字列のエスケープの回数が増えるという問題が発生するそうだ(詳しくはこちらを参照)。オプションが有効化されていることで、エスケープされてしまう文字としては5c問題に該当する文字になる。そこで、一般的な処理としてどのようにエスケープ処理のコードを書くのかということについて示しておく。今回はDB(PostgreSQL)に入れるための文字列がフォームから入ってきた場合を想定しておく。

<?php
function convert_str_for_query($string){
  if( get_magic_quotes_gpc() ){ // magic_quotes_gpcオプションの状態を取得
    $string = stripslashes($string); // 全体に対しバックスラッシュを取り除いた文字列を返す
  }
  $string = htmlspecialchars($string); // <や&のような文字列をエスケープする
  // 上のコードは一般的には表示の際に対策を立てておくためと考えられる
  $string = pg_escape_string($string); // PostgreSQLのクエリとなる文字列をエスケープする
  // ちなみにMySQLであれば、$string = mysql_real_escape_string($string); とする
  return $string;
}
?>

2014年10月28日火曜日

PHPmemo_day15

PHPの基本に関するメモ。参考にしているのはPostgreSQL徹底入門の第5章です。

  • header関数を用いることで、charsetを指定することができる。htmlのheadタグ内に書かなくてもよい。またリダイレクト先を指定することもできる。書き方は以下のコード参照。
  • <?php
    header('Content-Type: text/html; charset=UTF-8'); // 文字コードの指定
    header('Location: リダイレクト先のURL'); // リダイレクト先の指定
    ?>
  • pg_query_params関数は文字列を挿入してqueryを実行する関数であるが、自動的にエスケープ処理を行うことができる。これによりSQLインジェクションを回避することができる。
  • PHPにもCやJavaと同じく三項演算子がある。
  • $_REQUESTというスーパーグローバル変数がある。これはphp.iniのvariables_orderの項目でリクエストの内容をマージしたものが含まれている。普通は$_GET、$_POST、$_COOKIEの優先順位となる。リクエストメソッドに関係なく、$_REQUESTから参照すればパラメータの値を受け取ることができる。
  • htmlのコードとしてPHPを入れる場合はinclude関数でファイルを読み込む。同じファイルで何度も読み込む場合があるのでinclude_once関数自体はあるが一般的ではない(何度も読み込むミスを防ぐ場合に使う)。関数を読み込みたい場合はrequire_once関数を使うという棲み分けがある。
  • 最近のwebシステムにおけるユーザ登録ではメールを仮登録し、仮登録した先のメールアドレスに本登録用のURLを送ることでメールアドレスが正しいものであるか検証することが多い。メールアドレスの形式が妥当なものであるか判断するのは厳しくしすぎないようにしておく(厳密にRFCに従っているか調べるということまではしないということ)。
  • パスワードを単純にsha1関数で暗号化したものを保存しておくのは、レインボーテーブル(暗号化前の文字列と暗号化後の文字列がペアになったテーブル)により、容易にパスワードが破られる可能性があるためよくない。そこで、ソルトと呼ばれる、ランダムな文字列を適当につけてから暗号化することにより、レインボーテーブルによるパスワード対策を行うことができる。
  • require関数はリダイレクトすることになるが、このときリダイレクト先はURLではなく相対パスにしなければならない。ファイルの位置関係で指定の仕方が変わってくることに注意。
  • HTTPの仕様として、データは文字列でやりとりされるので、0という値がブラウザから渡されるとそれは数値ではなく文字列となっている。ただしPHPでは配列の添字の数字は数値として扱われる。以下の例では10は数値として、testという文字列はtestという文字列で扱われることになる。
  • <?php
    <a href="?a[]=1&a[10]=5&a[test]=10">link</a>
    ?>
  • pg_affected_rows関数はDELETEをクエリで実行した際に影響を受けた行数を返す関数である。これを利用して削除処理の成功/不成功を判定することができる。
  • ini_get関数でクッキーを使っているか確認できる。session_get_cookie_params関数でクッキーのパラメータを取得し、session_name()関数の返り値となるセッション名に空文字を設定することでセッションIDをクリアできる。サーバ上のセッションファイルはsession_destroy関数を呼び出せばOK。
  • トランザクション機能を使うと、一連の処理におけるSQLの実行が途中で失敗しても、その処理の直前までもとに戻すことができる。
  • <?php
    pg_query(コネクション名, 'BEGIN');
    (ここに書いたSQL文がトランザクションになる)
    pg_query(コネクション名, 'COMMIT');
    ?>

2014年10月25日土曜日

PHPmemo_day14

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第13章(処理制御)です。Smartyなど素のPHPとは関係のないところは省略。

  • スクリプトを途中で終了する場合にはexit関数、die関数を使う。前者は終了時にエラーメッセージを出さないのに対し、後者は終了時にエラーメッセージが出てくるようになっている。関数の引数に文字列を与えることでエラー時のメッセージを制御することができる。また、関数を引数に与えることで異常時でも正常終了させるなどすることができる。
  • 処理を一時停止するにはsleep関数を使う。これは秒単位で停止する。マイクロ秒単位で制御する場合はusleep関数を用いる。
  • エラーメッセージの抑制は変数、関数の前に@マークをつけることでできる。例えば@num = 10/0;のようにすればnumに関するエラーメッセージは出なくなる。
  • error_reporting関数はエラーを表示させるレベルを設定できる。関数を呼出した後からレベルが変化する。
  • error_log関数はエラーメッセージを任意のファイルに送信することができる。Webサーバのログ、メールなどにも書き込める。
  • trigger_error関数を使うと、ユーザエラーを発生させることができる。このとき、引数にE_USER_ERRORを指定することになる。
  • header関数でHTTPヘッダを送信することが可能になる。例えばLocationヘッダを指定することで移動先のURLを指定できる。
  • exec関数を利用すると外部プログラムを実行する。exec関数は返り値を要求しない場合に使う。system関数は標準出力を返してくる。
  • 外部プログラムでシェルを使うときはescapeshellargでシェル引数として与える文字列をエスケープしなければならない。これはexec、system関数の両方に対して言える。

2014年10月23日木曜日

PHPmemo_day13

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第12章(セッション/クッキー)です。

セッションはデータの受け渡しに使われる、ユーザの情報を継続して管理するための仕組みである。

  • セッション情報が置かれるディレクトリはphp.iniのsession.save_pathに書かれている。
  • セッションの自動開始はphp.iniのsession.auto_startを参照する。1であれば自動で始まる。
  • セッションの開始をスクリプトで制御するにはスクリプトの最初の方で、session_start関数を呼び出せばよい。
  • セッション変数はスーパーグローバル変数で、$_SESSIONである。$_SESSION["name"]="abc";のように設定すればよい。これはPHP5以上であれば問題なく利用できる。
  • 設定されたセッション変数はunsetで削除できる。設定されているかどうかはisset関数で調べられる。
  • セッション変数の保存先はsession_save_path関数でスクリプト側から調べることができる。ディレクトリがないと保存できずエラーになるので、そのような問題が発生した場合の調査に用いる関数である。
  • session_id関数で現在のセッションIDを取得することができる。クッキーが使用できる場合はクッキーにセッションIDが保存される。クッキーが使えない環境では、ページの遷移の度にセッション変数を遷移先に渡さないとセッション情報が引き継げない。
  • セッションハイジャックを防ぐ方法としてsession_regenerare_id関数を使う方法がある。この関数はセッションIDを新しいものに置き換えることができる。最近のPHPではsession_regenerate_id(TRUE)とすることで、古いセッションデータが削除され、よりセキュアになる仕組みが提供されている。
  • クッキーはユーザ側でデータを保存するための仕組みである。ただし、悪意あるサイトなどにクッキーの情報を盗まれる危険性があるので、カード番号などの重要情報はクッキーに設定しないようにしておく必要がある。
  • クッキーにデータを設定するにはsetcookie関数を用いる。参照する場合は$_COOKIE["変数名"]とする。setcookie関数の引数には変数名、値、有効期限、パス、ドメイン、HTTPSが必要か否かを与えることができる。
  • クッキーのデータを削除するには、setcookie関数の引数に古い有効期限を与えればよい。それにより特定の変数名のデータを削除することができる。削除されたことを確認するにはisset関数の返り値がFALSEになっていることを調べればよい。

2014年10月22日水曜日

PHPmemo_day12

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第2章(フォーム)後半です。

  • SQLコマンドに入る文字列をエスケープするにはmysql_real_escape_string(MySQL)、pg_escape_string(PostgreSQL)などの関数を用いる。ただし、php.iniでmagic_quotes_gpcをOnにしている場合、一旦stripslashes関数で文字列のエスケープ処理を解除してからDB専用の関数でエスケープ処理を行うのが良い。
  • フォームから受け取った値を用いてSQLクエリを構成する場合、数値は数値に変換してから挿入する。つまりintval関数で数値に変換するか、sprintfを使って数値を受け取る場合は"%d"として受け取ることになる。
  • フォームから受け取ったデータをsystem関数、exec関数を用いてシェルに渡すことがある。そのまま渡すと意図しないコマンドを実行される可能性があるので、シェルのメタ文字をエスケープするにはescapeshellcmd関数を用いる。
  • 特殊文字をエスケープするにはhtmlspecialchars関数を用いる。ただし「'」をエスケープするには関数の引数にENT_QUOTESを指定する必要がある。また、「"」、「'」をエスケープしない場合はENT_QUOTESを引数に与えることになる。
  • htmlタグをフォームから受け取った内容から取り除くにはstrip_tags関数を用いる。悪意のあるコード対策で用いられる。
  • 一部のタグだけ置換したいという場合はstr_replaceで置き換える。置換前と置換後の文字列を配列で指定することで複数のタグを一括で置換することもできる。
  • リンクに漢字を含むものについてはurlencode関数でエンコードを行う。これにより%5Cのように%と16進数から構成される文字列に置き換えられる。これをもとに戻すにはurldecode関数を用いる。
  • textarea内で改行をしても、表示では改行が含まれないようになっている。改行して表示するためにはnl2br関数を用いる必要がある。
  • アクセスの種類を判別するにはif( $_SERVER["REQUEST_METHOD"] == "POST" ){ ... }などとする。
  • explode関数で区切り文字を指定して、1つの文字列を配列に分割・収納することができるようになる。
  • mktime関数は日付をタイムスタンプ形式に変換できる。この関数では3月32日を4月1日のように自動的に解釈するようになっている。
  • checkdate関数は指定した年月日がグレゴリオ暦と矛盾がないかを調べる関数である。
  • mb_detect_encoding関数は文字コードの検出に使われる。引数で文字コードの検出の優先順位をつけておくことになる。
  • 文字コードの変換はmb_convert_encoding関数を使う。
  • 「$$変数名」という表記法がある。
  • $a = "abc";
    $$a = "xyz";
    echo $abc; // xyzと表示される。
    

2014年10月21日火曜日

CentOS 6でホスト名を書き換える

サーバのホスト名を書き換えるということは、仮想環境を利用するとしばしば起こりうることである。たとえば、VMwareに含まれる仮想マシンをコピーするテンプレートを作成するという機能を利用すると、この作業が必要になる。それはコピーして作られたホストは名前が重複しないようにしなければならないためである。さて、実際にホスト名を書き換える作業する際には次のような手順を踏むことになる。

  1. # vi /etc/hosts (ホスト名を書き換える)
  2. # vi /etc/sysconfig/network (名前解決の優先順位を書き換える)
  3. # hostname 書き換えたホスト名
  4. ログアウトして再度ログインしなおす
  5. ホスト名が変わっていることを確認する

名前解決において、/etc/hostsとDNSサーバのどちらが優先されるかということについては/etc/nsswitch.confを参照する。order: files,dnsなどと書かれている行があるはずである。filesが/etc/hosts、dnsがDNSサーバを意味しており、この順が名前解決の順序となる。普通はfiles,dnsの順序になっているはずである。また/etc/hostsには初期設定では自身以外の記述はないので、他のサーバにアクセスしようとすると、名前解決のためにDNSサーバを見に行くということになる。この仕組みを知っておくと、DNSサーバを構築しなくても、ごく小さな名前解決ができ便利である。

2014年10月20日月曜日

PHPmemo_day11

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第11章(クラス)です。

  • クラスの中の変数にはpublic、private、protectedが用いられる。varはPHP5では使わない方が良い。
  • コンストラクタメソッドは__construct()になる。デストラクタメソッドは__destruct()になる。
  • オブジェクトの参照のコピーは$obj2 = $obj1;でできる。オブジェクトをコピーするには$obj2 = clone $obj1;とする。
  • クラス中の静的変数・静的メソッドにはstaticを使う。この辺はJavaと変わらない。
  • 抽象クラスにはabstractをつける。継承されないクラスにはfinalをつける。
  • 定義されていないクラス、メソッド、フィールドが呼び出された場合、それぞれ__autoload、__call、__getメソッドをクラス内に用意しておくと、それらが自動で呼び出されることになる。エラー処理で使える。
  • get_decleared_classes関数で定義済みのクラス名を取得できる。
  • stdClassという内部で定義されているクラスを使うのは控えること。
  • get_class_methodsでクラス内に定義されている関数一覧を取得できる。
  • class_exists関数でクラスが存在するか調べることができる。存在していればTRUE、存在していなければFALSE。
  • method_exists関数でクラスのオブジェクト内にあるメソッド名が存在するか調べることができる。存在していればTRUE、存在していなければFALSE。
  • クラスのプロパティ(変数)を取得するにはget_class_vars関数を用いる。ただし、PHP5のprivateフィールドについては取得することはできない。また、オブジェクトのプロパティを取得するにはget_object_vars関数を用いることになる。

2014年10月17日金曜日

PHPからPostgreSQLに接続してデータを取得する

今回はPHPからPostgreSQLに接続してデータを取得するコードを書いてみます。DBについては既にインストールやアカウントの設定が終わっているものと仮定します。問題を簡単にするため文字コードについては考慮しませんが、DBからページに表示する際に文字コードを変換する関数も書いてみることにします。

$server = "localhost"; // 接続先のホスト
$dbname = "db_sample"; // データベース名
$user = "i_am_an_user"; // ユーザ名
$password = "passwd"; // パスワード
$conndef = "host=".$server." dbname=".$dbname." user=".$user." password=".$password; // 接続定義
$conn = pg_connect($conndef) or die("connection error"); // 接続

// SQLの実行(適当な例です)
$query = "SELECT * FROM mytable WHERE id <= 10";
$result = pg_query($conn, $query) or die("SQL error");
// 結果から各種情報を取得する
$nrow = pg_num_rows($result); // 行数(件数)の取得
$nfield = pg_num_fields($result); // 列数の取得

// 表示
for( $i = 0 ; $i < $nfield ; $i++ ){
  echo pg_field_name($result, $i)." "; // タイトルの表示
}
echo "\n";
while ($row = pg_fetch_array($result)) { // 1要素ずつ取得する
  for( $i = 0; $i < $nfield ; $i++ ){
    // $row["id"]などとしてもデータを取得することができる。
    // その場合はpg_fetch_array($result, $i, PGSQL_ASSOC)として1要素を取得することになる。
    echo $row[$i]." "; // 順番に各内容を表示
  }
  echo "\n";
}

pg_close($conn); // DB操作が終わったら切断

// DBから取得した文字列に対して文字コードを変換するための関数
// DBの文字コード
$db_encode = "UTF-8";
// 表示の際に使う文字コード(文字コードはhtmlに指定されているはずである)
// もしかするとApacheなどWebサーバの方で強制的に指定されているかもしれないので
// そちらの設定も確認しておくこと。全部統一しておけば、とりあえず安心できるだろう。
$disp_encode = "UTF-8";
function convert_encoding($string, $from, $to){
  $detected_encode = mb_detect_encoding($string, $from.", ".$to);
  if( $detected_encode and $detected_encode != $to ){
    return mb_convert_encoding($string, $to, $detected_encode);
  }else{
    return $string;
  }
}

MySQLとPostgreSQLでは引数に与えるクエリと接続定義の順序が逆になっている点に注意。

2014年10月16日木曜日

PHPmemo_day10

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第10章(ディレクトリ)です。

  • mkdir(ディレクトリ名, パーミッション)で指定したディレクトリを作成できる。返り値はディレクトリ作成の成功(非0)、失敗(0)である。
  • is_dir(ディレクトリ名)でディレクトリの存在を確認する。
  • dirname(ファイルパス)でファイルのディレクトリが分かる。絶対パスを取得するにはrealpath関数を用いる。
  • diskfreespace(ディレクトリ名)でディレクトリが使用可能な容量を取得できる。
  • rmdir(ディレクトリ名)で指定したディレクトリを削除する。返り値はディレクトリ削除の成功(非0)、失敗(0)である。
  • dir(ディレクトリ名)でディレクトリをオブジェクトとして取得する。ディレクトリの中身はreadメソッドで順に取得できる。lsコマンドと同様に、ディレクトリが含まれる点に注意。参照が終わったらcloseメソッドを呼ぶこと。
  • PHP5ではscandir関数を用いることで、指定したディレクトリに以下にあるファイル一覧を配列で取得できる。

2014年10月10日金曜日

PHPmemo_day9

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第9章(ファイル)の後半です。

  • readfile(URL)でhtmlのページを読み込みできる。ページの埋め込みに使える。
  • get_mata_tags関数でhtmlからメタタグを読み込みできる。返り値は配列であり、descriptionやkeywordsといったインデックスでメタタグの内容を参照できる。
  • fgetssはhtmlタグを取り除いた形でhtmlを1行ずつ読み込む。trim関数を組み合わせることでインデントの空白も除去して使うことが多い。
  • 外部ファイルに定義した関数を呼び出すにはrequireかinclude関数を用いる。前者は読み込みファイルがないと致命的なエラーになるのに対し、後者は警告で済むという違いがある。
  • 一度だけファイルを読み込むのであれば、require_onceかinclude_once関数を用いる。
  • include関数の戻り値でファイルがインクルード済か調べられる。読み込み済なら1が返される。@include(~)とすればエラーメッセージを抑制できる。
  • 配列からカンマ区切りの文字列(CSVの1行)を生成するにはimplode(",", $array)が一般的である。
  • fgetcsv関数では区切り文字を指定することでCSVファイルの1行を配列で取得できる。あるいはlist関数で変数としてfgetcsv関数の返り値を受け取ることもある。
  • getimagesize関数の返り値で指定したファイルが画像であるか否か判定することができる。

2014年10月1日水曜日

PHPmemo_day8

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第8章(ファイル)の前半です。

  • die関数はexitと同じでスクリプトを終了するという意味がある。以下のコードはfopenに失敗した場合(ファイルが存在しない場合など)にdieが呼ばれる。
  • $file = fopen($target, "a") or die("ファイルオープンに失敗しました");
    flock($file, LOCK_EX); // ファイルの排他的ロック
    fputs($file, "abc</br>"); // 改行をつけてabcとファイルに書き込む
    flock($file, LOCK_UN); // unlock、ファイルの排他的ロックを解除する
    fclose($file);
  • 共有ロックはLOCK_SH、ロック中に他のflock()でロックさせたくなければLOCK_NBをflock関数の引数で指定する。
  • fopenはaで追記、wは上書きという意味になる。rは読み込み専用。xというオプションもある。+をつけることで読み書きの両方ができるようになる。
  • tmpfile()関数を用いると、一時ファイルを作成できる。ここにデータを書き込むなどすればよい。fclose()で一時ファイルを閉じると、ファイルは自動的に削除される。
  • file_put_contents関数を使うと、fopenでファイルを開かなくても指定したファイルに書き込みができる。fcloseなども不要になる。
  • ファイルの読み込み時はファイルが存在しないとエラーになるので、@をつけてエラーメッセージを非表示にする手法が用いられる。
  • // 読み込み(r)なので、@をつけないとエラーメッセージを抑制できない
    $file = @fopen($target, "r") or die("ファイルオープンに失敗しました");
    flock($file, LOCK_EX); // ファイルの排他的ロック
    while( feof($file) ){
     echo fgets($file, 1000)."</br>"; // 1行ずつ表示。1000と指定すると999バイトまで読み込める。
    }
    flock($file, LOCK_UN);
    flose($file);
  • fgetsに代わり、fgetcとすると1バイトずつ読み込むことになる。freadは指定したバイト数だけ読み込んでいく。
  • ファイル全体をまとめて読み込む場合には、fread関数とファイルサイズを調べるfilesize関数を組み合わせる方法がある。その他、file_get_contents関数、file関数がある。file_get_contents関数はファイルの中身を1つの文字列として取得する。file関数はファイルの内容を配列で入れる(改行なんかで1つの要素ごとに区切っているっぽい)。
  • ファイルの存在確認にはfile_exists関数(返り値はboolean)が使える。
  • rewindはファイルポインタを先頭にセットするための関数である。
  • fileatime関数はファイルの最終アクセス時刻を調べるための関数である。最終更新時刻はfilemtime関数で調べる。
  • ファイルの許可属性はfileperms関数で調べられる。ただし、出力結果はlinuxのパーミッションのように0~7の3桁の数字でもないので注意が要る。
  • 拡張子のチェックはpathinfo関数の返り値のインデックスextensionを使うとよい。pathinfoはパス名に関する情報を得るための関数である。インデックスbasenameにはファイル名(拡張子付)が含まれている。
  • ファイルの読み込みができるかについてはis_readable関数を、書き込み可能かどうかはis_writable関数を使う。実行可能かどうかについてはis_executable関数を使う。
  • copy(from, to)でファイルコピーができる。ファイルのコピー先は強制的に上書きされる。
  • rename(from, to)でファイル名の書き換えができる。変更先にファイルが既に存在しているとエラーになるので、そのような場合にエラーメッセージを抑制したい場合は@rename(from, to)とする。
  • unlink($file)で$fileを削除できる。削除対象がないとエラーになるので、file_existsで一度調べてから削除することもある。あるいは@unlink($file)のようにすることもある。

2014年9月30日火曜日

PHPmemo_day7

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第7章(配列)です。

  • array関数で配列を作成できる。中身は可変長引数であり、先頭から順に参照できる。参照する際にはforeachを使う方法がある。
  • $v = array("a", "b", "c");
    foreach($v as $elem){
     echo $elem;
    }
  • array関数で単に値のみの配列とした場合、添字は0から始まる。
  • array関数はmapのように扱うこともできる。つまり、次のような配列を作り、参照することができる。インデックス(mapだとキー)については数字でも文字列でも可。
    $v = array("first" => "a", "second" => "b", "third" => "c");
    echo $v["second"]; // "b"と表示される
  • 配列の一括表示にはprint_r関数が使える。
  • インデックスは一部だけ指定できる。途中に数字でインデックスを指定すると、その後でインデックスを省略したものについては指定した数字に続く数字がインデックスとして指定される。
  • count関数は配列の要素数をカウントできる。
  • array_count_values関数は配列の要素の出現頻度をカウントできる。
  • 配列の結合はarray_merge関数が使える。同じ文字列型のインデックスがある配列を結合すると、インデックスの値は後で指定した配列で上書きされる。上書きしてほしくない場合は、array_merge_recursive関数を使う。こちらはインデックスに対応する値を単一の値ではなく、配列とすることにより、上書きを回避している。
  • sort関数は配列の要素を並び替える。インデックスは無視される(要素の並び替えに合わせてインデックスも並び替えられるわけではない)。2番目の引数にSORT_STRINGとすると、値を文字列とみなしてソートすることができる。数値として並び替えるのであれば、SORT_NUMERICと指定する(省略した場合はこっちが優先される)。
  • 配列を逆順にするにはarray_reverse関数を用いる。インデックスも並び替えられる。
  • ksort関数を用いると、インデックスの昇順で並び替え、krsort関数を用いるとインデックスの降順で配列を並び替える。
  • インデックスも合わせて値を並び替えるにはsort関数ではなくasort関数を用いる。降順に並び替えたければarsort関数を用いる。
  • array_pad関数は配列を拡張して、指定した値で配列を要素を埋めていく関数である。
  • range(a, b)とすると、array(a, a+1, ..., b)のように、指定した範囲の整数を値として持つ配列を作成できる(Pythonのrangeはbを含まないが、PHPは含む点に注意)。3番目に数値の間隔を指定することもできる。
  • array_shift関数は配列の先頭要素を削除する。返り値は削除された先頭の値となる。逆に、先頭に追加するのはarray_unshift関数で、その返り値は要素数となる。
  • array_popは配列末尾の値を削除する。返り値は削除された末尾の値となる。逆に、末尾に値を追加するのはarray_push関数で、その返り値は要素数となる。
  • 途中にあるものを複数削除するにはarray_splice関数がある。array_spliceには値を置き換えるという機能もある。
  • 配列からランダムに要素を取り出すのはarray_rand関数である。第2引数で値を指定することにより、ランダムに取り出す件数を指定できる。
  • shuffle関数を用いると、配列をランダムに並び替える。元データを破壊することになるので、その点については注意。
  • 配列の一部切り出しはarray_slice関数を用いる。
  • 配列のコピーは$a2 = $a1が単純である。あるいはarray_aliceで先頭から切り出すと書いてもよい。
  • array_sum関数は配列のデータを合計する機能がある。"10点"は10と解釈する。"p.10"は数値として評価されない(無視される)。
  • 配列の各要素を関数で処理するにはarray_walk関数がある。array_walk関数は配列とユーザ定義関数を指定する。従って、PHPに初めからある関数を呼び出したい場合は、ユーザ定義関数の中で呼び出すことになる。
  • compact関数は変数を配列にセットするための関数である。
  • $a = 1;
    $b = 2;
    $array = compact($a, $b); // a, bというインデックスが配列に含まれる
  • 配列から要素に展開するにはlist関数を用いる。
  • $array = array(1, 2);
    list($a, $b) = $array; // $a, $bという変数に1, 2が入る
  • ある要素が配列中にあるか判定する関数としてin_array関数がある。返り値はTRUE、FALSEのどちらかになる。
  • ある要素が配列中にあればそのインデックスを返す関数としてarray_search関数がある。存在しないか調べるには返り値に対しis_numeric関数で判断すればよい(インデックスがすべて数字であればの話だが)。

2014年9月27日土曜日

PHPmemo_day6

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第6章(日付)です。

  • time関数
    • 現在時刻を取得するための関数。1970年1月1日の0時0分0秒からの経過秒数を取得できる。
  • date関数
    • time関数の内容から整形して出力する。YmdHis(年月日、時分秒)を使って整形する。
  • microtime関数
    • 現在時刻をマイクロ秒まで取得する。返り値のフォーマットは"小数部 整数部"となっているので、文字列をスペースで区切り配列に入れるよう explode(" ", $ret);とすることでarrayとして扱えるようになる。
  • idate関数
    • dateの一部を返す関数。PHP5以降で使える。
  • getdate関数
    • 日付の値を別々に取り出すための関数。$d = getdate();と呼び出すとarrayが返されるので、$d["year"]のようにして参照する。
  • mktime関数
    • タイムスタンプ(1970年1月1日の0時0分0秒からの経過秒数)を得るための関数。指定日数後の日付も計算できる。つまり引数に1月32日と入れられても自動的に2月1日と換算してくれるということである。また0日と指定すると、前月の最終日に自動的に変換される。
  • strtotime関数
    • 日付の文字列フォーマットからタイムスタンプを得るための関数。こちらも指定日数後の日付を計算できる。

2014年9月26日金曜日

PHPmemo_day5

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第5章(数値)です。

  • 0による除算はエラーメッセージが出てくる。
  • bindecは2進数から10進数へ、decbinは10進数から2進数に数値を変換する。16進数を使って変換する場合はhex、8進数ならoctに置き換えれば、同様の関数を利用できる。
  • ceilは切り上げ、floorは切り捨て、roundは四捨五入のための関数である。
  • maxやminは配列に対しても可変長引数に対しても最大、最小を計算して返してくれる関数である。
  • number_formatを利用すると、3桁ごとに区切って数値を表示することや、小数点以下何桁まで表示するかといったことを指定できる。日本と海外では桁数の多い数字の書き方が異なるので、その変換に使える。またフランス流の表記では1 234 567のように,でなく空白を用いて数字を書くので、そのような場合にも用いられる。
  • rand関数、mt_rand関数は乱数を発生させるための関数である。最小値と最大値を指定して発生させる乱数のレンジを指定できる。getrandmax関数、mt_getrandmax関数を用いることで乱数の既定の最大値が分かる。
  • intval関数により、文字列の整数値を数値としての整数値に変換できる。ただし、この関数は仕様がやや複雑なので、使うときにはリファレンス必須。

2014年9月23日火曜日

PHPmemo_day4

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第4章(文字列)です。

  • 文字列の結合と代入を一度に行うための演算子は.=である
  • substr関数は部分文字列を抽出するための関数である。
  • $s = "0123456789";
    substr($s, 5); // "56789"になる。添字で5以降が抽出される。
    substr($s, -2); // "89"になる。最後の2文字を抽出する。
    substr($s, 0, 2); // "01"になる。添字で0から1までが抽出される。
  • substr関数はマルチバイト文字に対して使うべきではない。マルチバイト文字に対応するmb_substr関数を使うべきである。mb_substr関数では読み込む文字のコードを指定することができる。
  • str_shuffle関数で文字列をランダムに並び替えることができる。
  • str_replace関数は処理対象の文字列、置換対象の文字列、置換後の文字列を指定することで、返り値で処理対象後の文字列が得られる。PHP5では第4引数に変数を与えると、置換した回数が返される。
  • ereg_replace関数は正規表現パターンを利用して文字列を置換できる。
  • $s = "012-abc";
    $p = "[0-9]";
    $r = "*";
    echo ereg_replace($p, $r, $s); // "***-abc"に置換される
  • preg_replace_callback関数を用いると、パターンにマッチした部分をどのように置換するかを関数で定義できるようになる。callbackなので、指定したパターンが見つかる度に指定した関数が呼ばれることになる。
  • 文字列の前後の空白を取り除くにはtrim関数を用いる
  • 文字列の比較にはstrcmp関数を用いる。大文字小文字を区別せず比較するのであれば、strcasecmp関数を用いればよい。
  • strtoupper、strtolower関数により、文字列をすべて大文字、小文字に変換することができる。
  • ucfirst、ucwords関数を用いると、文字列の文章の先頭、文字列の各単語の先頭を大文字に変換することができる。
  • explode関数は指定した文字で文字列を分割する。返り値はarrayになる。
  • n文字ごとに文字列を分割したいということであれば、str_split関数を用いればよい。
  • 文字列を繰り返し結合するにはstr_repeat関数がある。
  • 文字列中に特定の文字列が出現する回数を求める関数として、substr_count関数がある。
  • strlen関数はバイト単位の文字列の長さを返す。従って、ひらがなは2バイトなので2文字としてカウントされる。ひらがらのようなマルチバイト文字を1文字としてカウントするのはmb_strlen関数である。
  • mb_convert_kana関数を用いると全角と半角間の変換ができる。日本語限定と思って使うこと。

2014年9月20日土曜日

PHPmemo_day3

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第3章(変数、定数)です。

  • echoで文字列と変数の間にスペースを入れずに出すには{$var}のように{}で囲えばよい
  • 変数の型を調べるにはgettype関数を利用する
  • 変数の型変換にはsettype関数を利用する
  • var_dump関数を利用すると、変数の方に関する情報と値をまとめて出力できる
  • get_defined_vars関数を利用すると定義済みの変数情報一覧を取得できる。
  • define関数で定数を定義できる。C言語の#defineみたいなものとみてよいだろう。
  • defined関数で定数が定義済みか調べられる。
  • define("EXP", 2.718)のように定義したEXPを参照するにはEXP、あるいはconstant("EXP")とする。
  • __FILE__はPHPコードの書かれたファイル名、__LINE__はコードの行番号を表す定数である。
  • M_PIは円周率、M_SQRT2はルート2を表す定数である。
  • get_defined_constants関数で定義済みの定数一覧を取得できる。
  • get_defined_constants関数のように一覧を取得して表示したいのであれば、print_r関数が使える。print_r関数はデバッグにも使える。
  • $_SERVER["HTTP_USER_AGENT"]はブラウザの情報を、$_SERVER["HTTP_REFERER"]はリンク元を、$_SERVER["REMOTE_ADDR"]はアクセス元のIPアドレスを表す(PHP4.2.0以降)

2014年9月18日木曜日

PHPmemo_day2

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第2章前半です。 コードを書いて紹介するのは大変なので、C言語やJavaと違うところを主に取り上げていきます。

  • フォームからPOST送信された値を受け取るときには$_POST["content"]とすればnameがcontentのデータを受け取れる。
  • php.iniのregister_globalsをONにすると$contentで参照できるようになるが、セキュリティの都合上OFFにするのが一般的
  • @$_POST["content"]とすることで、contentが初期状態で何も設定されていない状態でもエラーが出なくなる
  • $_SERVER["PHP_SELF"]は現在表示中のURLを表すサーバ変数である
  • $HTTP_POST_VARS["content"]のようにPOST送信されたデータを受け取ることもできるが、php.ini-recommendedでは無効になっている。
  • php.iniにはdisplay_errorsという設定項目がある。これはエラーを画面に出すためのオプションであり、デバッグに使える。
  • $_GET["type"]などとすればGET送信されたURLのtype=の値を取得することができる。
  • フォームから送信されるデータはstring型である。
  • フォームから変数を受け取って、同じ変数名に受け取った値を設定するには、extract関数を使う。ただし、extract($_POST)のように記述すると、ユーザの入力をそのまま出すのでエスケープ処理などをした方がよいとされる。
  • フォームからある変数が飛んできているか調べるにはisset関数を利用する。if文や三項演算子を用いて変数の有無で変数を設定する際に使える。
フォームからの入力内容を確認するためによく使われる関数についても紹介しておきます。
  • function_exists
    • 引数の文字列の関数名が定義されているかを調べるための関数
  • strlen
    • 文字列の長さを調べるための関数
  • empty
    • 空、または0でTRUEを返す関数
  • isset
    • 変数が定義されていればTRUEを返す関数
  • stristr、strstr
    • 文字列のマッチングで利用する関数。前者は大文字と小文字の違いをignore(無視)するが、後者では区別している。
  • is_numeric
    • 文字列が数字として解釈できるのであればTRUEを返す関数。数字は半角でないとTRUEにならない。
  • ctype_digit
    • is_numericに似ているが、小数点が含まれるとFALSEになる点が異なる。あとは同じ。
  • ctype_loert、ctype_upper
    • 引数の文字列が小文字、あるいは大文字だけからなるかを調べる関数
  • checkdate
    • 引数で与えた月、日、年の数値がグレゴリオ暦で正しい日付か(存在する日付であるか)調べる関数

2014年9月17日水曜日

PHPmemo_day1

PHPの基本に関するメモ。参考にしているのはPHPによるWebアプリケーションスーパーサンプル第2版の第1章です。 コードを書いて紹介するのは大変なので、C言語やJavaと違うところを主に取り上げていきます。

  • PHPのコードは<?~?>で囲う
  • 変数は$i=(値)のように定義する
  • echo、printで文字列出力を行う。HTMLをechoで出力する方法もある。
  • echoをダブルクォートで囲うと変数は変数の値に解釈され、シングルクォートで囲うと変数名は文字列と解釈される
  • $s = "abc";
    echo "string=$s"; // string=abcと表示される
    echo 'string=$s'; // string=$sと表示される
  • 文字列の結合はドット(.)で行う
  • 空文字、null、0も論理値のFALSEとして扱われる。それ以外はTRUEになる。
  • 関数にはデフォルト値を設定することができる。
  • func(1)とcall_user_func(func, 1)は同値になる

2014年8月17日日曜日

TopCoder SRM487 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文についておおまかに説明する。

ウサギたちはプログラミングは好きだが、プログラミングの試験が好きではない。黒、グレー、白の3匹のウサギは最終試験を終えた。ウサギたちが問題について議論している間に、教授がやってきて、"黒いやつ、お前は0点だ、知識を確かなものにするために、グレーと白が取った点数の最大値の合計点を計算するプログラムを書け"といった。

試験はN問からなるものであった。ウサギたちは同じ問題を提示される。各問題に対し、その答えとしてA~Zのアルファベットの大文字を書かなければならなかった。問題に対し、1つの文字のみが正しいものとされ、他の25文字は正しくない回答となっている。正解は1点となり、ウサギの得た点数は問題に正解した数に一致する。

black、gray、whiteという黒、グレー、白のウサギが書いた回答を表す文字列が与えられる。それぞれの文字列はN文字からなり、文字列のi番目の文字はそれぞれのウサギのi番目の回答を表すものとする。黒ウサギの点数が0のときに、グレーと白のウサギが獲得しうる点数の合計の最大値を返せ。

私の回答は以下の通り。

public class BunnyExamAfter {

 public int getMaximum(String black, String gray, String white) {

  int points = 0;
  for( int i=0 ; i<black.length() ; i++ ){
   if( black.charAt(i) == gray.charAt(i) &&
    black.charAt(i) == white.charAt(i) ){
    // pass
   }else if( black.charAt(i) != gray.charAt(i) &&
     black.charAt(i) == white.charAt(i) ){
    points++;
   }else if( black.charAt(i) == gray.charAt(i) &&
     black.charAt(i) != white.charAt(i) ){
    points++;
   }else if( black.charAt(i) != gray.charAt(i) &&
     black.charAt(i) != white.charAt(i) &&
     gray.charAt(i) == white.charAt(i) ){
    points += 2;
   }else if( black.charAt(i) != gray.charAt(i) &&
     gray.charAt(i) != white.charAt(i) ){
    points++;
   }
  }
  return points;
 }

}

得点は220.72/250、1回のsubmitでシステムテストクリア。

2014年8月6日水曜日

TopCoder SRM486 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文についておおまかに説明する。

奇妙な省略形が扱いにくい携帯機器でテキストを書くのにしばしば用いられる。アルファベットと空白からなるテキストをエンコードする方法の1つに次のものがある。

  • 空白はそのままで、各単語は単語ごとにエンコードされる。ここで単語とはアルファベットの続く連続した文字列をいう。
  • もし単語が母音のみからなる場合、それはそのまま書かれる。
  • もし単語が1つ以上の子音を含むのであれば、直前に別の子音がない子音のみ書く。母音を買い手はならない。
  • 上記の規則において、母音は'a', 'e', 'i', 'o'と'u'である。他の文字は子音と考える。

例えば、"ps i love u"というのは、"p i lv u"と省略され、一方、"please please me"は"ps ps m"と略されるであろう。 originalという文字列が引数で与えられたとき、先述の方法で省略されたメッセージを返すメソッドを作成せよ。

私の解答は以下の通り。

public class TxMsg {

 public String getMessage(String original) {
  StringBuilder msg = new StringBuilder("");
  String[] strs = original.split(" ");
  for( int i=0 ; i<strs.length ; i++){
   if( isAllVowel(strs[i]) ){
    msg.append(strs[i] + " ");
   }else{
    msg.append(makeEncodedMessage(strs[i]) + " ");
   }
  }
  // if文の後者により、最後に空白ができる可能性があるので、trimを行う
  return msg.toString().trim();
 }

 private static boolean isAllVowel(String s){ // 入力がすべて母音か判断
  char[] vowels = {'a', 'e', 'i', 'o', 'u'};
  for( int i=0 ; i<s.length() ; i++ ){
   boolean isvowel = false;
   for( int j=0 ; j<vowels.length ; j++ ){
    if( s.charAt(i) == vowels[j] ){
     isvowel = true;
     break;
    }
   }
   if( ! isvowel ) return false;
  }
  return true;
 }

 private static String makeEncodedMessage(String s){
  char[] vowels = {'a', 'e', 'i', 'o', 'u'};
  StringBuilder sb = new StringBuilder();
  boolean prevConsonant = false;
  boolean currentConsonant = true;

  for( int i=0 ; i<s.length() ; i++ ){
   currentConsonant = true;
   for( int j=0 ; j<vowels.length ; j++ ){
    if( s.charAt(i) == vowels[j] ){
     currentConsonant = false;
     break;
    }
   }
   if( !prevConsonant && currentConsonant ){
    sb.append(s.charAt(i));
   }
   prevConsonant = currentConsonant;
  }
  return sb.toString();
 }

}

得点は158.01/250、1回のsubmitでシステムテストクリア。

2014年7月30日水曜日

Raspberry PIでSSHの初期設定時に発生したエラーを回復する方法

Raspberry PIの初期設定中に、「Initial ssh key generation still running. Please wait and try again.」 というメッセージが出てきて困ったことがありました。何が原因で発生したのかよく分からないのですが、 最初の起動時に接触が悪かったのため、一度設定前に電源を落とすなどしたことが可能性として考えられました。 さて、この状態になった場合、次の鍵を作り直すためのコマンドを入力することによってSSHが使えるようになります。

作業時には初期状態(User:pi、Password:Raspberry)のアカウントを利用しました。なのでsudoでコマンドが実行ができます。

# rm /var/log/regen_ssh_keys.log
# sudo rm /etc/ssh/ssh_host*
# sudo ssh-keygen -A

個人的にはログを消すとうまく動作するというのはあまり納得できません。 logではなくlockという拡張子のファイルを削除するのであれば理解できるのですが。

2014年7月19日土曜日

Firefoxで戻るボタンを押した際に二重送信防止を解除する

今回はFirefox(テストで利用したバージョンは30.0)における厄介な挙動をJavaScriptで解決しようというお話。 IE 11や最新のChrome(35系)では特に気にする必要はないものです。

フォームで二重押下を防止するために、1度ボタンを押すとボタンの状態をdisabledにするということがあります。 そこまでは何も問題ないのですが、Firefoxではボタンを押してsubmitをした後に、戻るボタンを押すとdisabledの状態が継続しており、 再度submitができない状態になってしまいます。もう一度戻るボタンを押すとsubmitできるようになるのですが、 その挙動は一般的にユーザが想定していないものであるはず。

そこで、jQuery(利用したバージョンは1.11.0)を利用して、 一度戻るボタンを押すだけでdisabledの状態が解除できるようにしてみました。コードは以下のようになります。

<script type="text/javascript"><!--
$(document).ready(function() {
    $(window).unload(function(){});
    $('#button').attr('disabled', false);
});
--></script>

1行目はDOMを構築した後に実行せよという意味です(おまじないと思って差し支えないでしょう)。 2行目はBackForwardCacheを無効にせよという意味になります。元のページに遷移した際にキャッシュを使うなという意味になります。 つまり、ボタンを押したという状態を使うなということになります。 3行目はボタンにdisabled属性をfalseにせよという意味で、ボタンを利用可能にするという意味になります。 初期状態はfalseでなければならないので、明示的に設定しました。

これにより、ボタンを1度叩いてdisabledになった状態でブラウザの戻るボタンを押しても、disabledの状態にならなくなります。 ただし、フォームにあった情報(入力したテキスト等)はすべて落ちてしまうので、再入力が必要になります。 もっとも、それは仕様としてしまっても良いとは思いますが。

2014年4月26日土曜日

jQueryの個人的メモその2

$(document).ready(function(){..})は$(function(){...})のように省略できる。

要素を指定して何かをする場合は次のように書く。セレクタについてはクラス、ID、要素が指定できる。

 $(セレクタ).メソッド(パラメータ);

何かの要素の下にある要素を指定する場合はセレクタをスペースを空けて並べればよい。以下の例ではpタグの下にある.warn要素で囲まれた箇所の色を赤に変更している。

 $("p .warn").css("color", "red");

*(ユニバーサルセレクタ)を使うと、ワイルドカードのように振る舞うことになる。pタグの下にある要素で囲まれたものすべてについて色を赤に変えることになる。pタグの下にあるセレクタ以下にある要素が変わるのであって、pタグの直下にあるものについては変わらない。

 $("p *").css("color", "red");

セレクタの箇所はカンマで区切ることで、複数の要素をまとめて指定することができる。

 $(".left, .right").css("color", "red");

チャイルドセレクタは直下にあるものに絞る。上の例は子孫セレクタであり、深さを問わない指定方法であるという点で異なる。

 $("p > .warn").css("color", "red");

隣接セレクタは連続する2つの要素を指定し、2つ目に指定したものが指定されたものになる。以下ではh2要素に隣接するh3要素が指定されることになる。

 $("h2 + h3").css("color", "blue");

間接セレクタは同じ親を持つ要素で指定した要素より後ろにあるものすべてを指定する。以下ではliにsecondというidを割り振っておけば、ulという親があるため、secondより後ろにあるli要素の色がすべて赤になる。

 $("#second ~ li").css("color", "red");

CSSにおける要の素指定方法とjQueryのセレクタ指定方法は良く似ていることが確認できる。

2014年4月21日月曜日

jQueryの個人的メモその1

HTMLのヘッダにjQueryのライブラリへのパスを設定しておくことが多い。ページの表示速度を考慮してjQueryの読み込み後回しにするため、bodyタグの一番最後に書くこともある(=多くの場合、その後ろはhtmlタグを閉じるだけであろう)。ローカルにダウンロードしてそのパスを設定してもよいし、CDN(Contents Delivery Network)に置かれているjQueryのライブラリを指定して読み込んでも良い。CDNは例えば以下に挙げたURLを指定することになる(詳しくはこちらを参照)。なお、外部との通信が発生するので、通信内容を暗号化する目的でhttpsでURLを指定することも考慮すべきである(以下のURLの場合、Googleの方ではできる)。

  • http://code.jquery.com/jquery-1.11.0.min.js
  • http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js

以下の例ではwarnクラスの要素を赤にする。例えば注意書きを囲うときに使える。

$(document).ready(function(){
 $(".warn").css("color", "red");
}

上のコードの1行目の意味はページがjQueryを実行する準備ができたらという意味である。これを書かないでいると、読み込む前にwarnクラスの要素が出てこないので、warnクラスの要素の色を変えることができない。なお、readyを用いた場合、画像の読み込みは後回し(jQueryのライブラリを読み込んだ後)となる。画像を読み込んでからjQueryのライブラリの読み込みを実行したい場合は次のようになる。画像をjQueryで変化させたいときに使うことになる。

$(window).on("load", function(){
 $(".warn").css("color", "red");
}

ただし、画像に手を加えないのであれば、パフォーマンスを考慮して前者の書き方を採用することが一般的である。

2014年3月15日土曜日

TopCoder SRM485 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文についておおまかに説明する。

マナオはすべての商品が正の整数の価格を持つ国に住んでいる。彼は電子レンジを売る会社を立ち上げており、それらを売るのに最適な価格を決める必要がある。最近彼は新しい心理学的な発見を聞いた。それは価格の小さい方の桁に9が続くにつれて、消費者に魅力的になるというものである。たとえば9099は9が2つ、8909は1つ9が最後にあるので、前者が魅力的ということになる。

マナオはminPriceを下回らない価格でのみ売る余裕があり、消費者はmaxPriceを超えない価格でしか電子レンジを買わないということを把握している。minPriceとmaxPriceの間で9が最大限後ろに続く数のうち最大のものを見つけることでマナオを手助けせよ。

public class MicrowaveSelling {

 public int mostAttractivePrice(int minPrice, int maxPrice) {
  int nNine = 0;
  int price = minPrice;
  for( int i=minPrice ; i<=maxPrice ; i++ ) {
   int nCurrent = trailing(i, 9);
   if( nCurrent >= nNine ) {
    price = i;
    nNine = nCurrent;
   }
  }
  return price;
 }
 private int trailing(int num, int target){
  int n = 0;
  while( num >= 1 ){
   if( num % 10 == 9 ){
    n++;
   }else{
    return n;
   }
   num /= 10;
  }
  return n;
 }

}

得点は173.37/250、3回目のsubmitでシステムテストクリア。ちなみにtrailingは「後端の」という意味です。

2014年3月12日水曜日

TopCoder SRM484 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文についておおまかに説明する。

カード1には1~8の整数、カード2には1~4、9~12の整数、カード3には1、2、5、6、9、10、13、14、カード4には1~15の奇数が書かれている。太郎は花子に対して、1~16の整数を1つ思い浮かべ、それが各カードに含まれているか否かを尋ねた。その答えで整数は唯一に定まる。引数のanswerという文字列にはYないしNという文字が入り、カードiに数字が含まれているか否かの回答はi番目の文字に対応しているものとする(Yなら含まれる、Nなら含まれない)。このとき、花子が想像している数字を返すメソッドを作成せよ。

import java.util.ArrayList;

public class NumberMagicEasy {

 public int theNumber(String answer) {
  int[][] numbers = {{1, 2, 3, 4, 5, 6, 7, 8},
    {1, 2, 3, 4, 9, 10, 11, 12},
    {1, 2, 5, 6, 9, 10, 13, 14},
    {1, 3, 5, 7, 9, 11, 13, 15}
  };
  int[] pts = new int[16];
  if( answer.indexOf("Y") == -1 ) return 16; // 全部Nなら16
  for( int i=0 ; i<answer.length() ; i++ ){
   if( answer.charAt(i) == 'Y' ){
    for( int j=0 ; j<numbers[i].length ; j++ ){
     pts[numbers[i][j]-1] += 1;
    }
   }else{
    ArrayList<Integer> al = new ArrayList();
    for( int j=1 ; j<16 ; j++ ){
     al.add(j);
    }
    for( int j=0 ; j<numbers[i].length ; j++ ){
     if( al.contains(numbers[i][j]) ){
      int idx = al.indexOf(numbers[i][j]);
      al.remove(idx);
     }
    }
    for( int j=0 ; j<al.size() ; j++ ){
     pts[al.get(j)-1]++;
    }
    al.clear();
   }
  }
  for( int i=0 ; i<pts.length ; i++ ){ // 全部の条件にマッチする数字を返す
   if( pts[i] == numbers.length ) return i+1;
  }
  return 16;
 }

}

得点は117.24/250、1回のsubmitでシステムテストクリア。削除の仕様に対する設計がちょっと面倒でした。方針としては、各質問の回答で条件に合う数字に1点、合わない数字は0点をつけて、4回の質問で4点(=全部の条件に合う)になったものが答えになるように実装しました。

2014年3月3日月曜日

TopCoder SRM483 Div2 250Pts

このTopCoderの問題はこちらで見ることができる(要TopCoder登録 & 問題文は英語)。問題文についておおまかに説明する。

エリーのやっかいな教育アシスタントのトーブはエリーに次のパズルを与えた。42->1、1337->0、669->3(もう少し続く)。このとき45678は何になるか?エリーは考えるのが早く、問題を解く直感のおかげで解法を思いついた。Googleである。答えは10進数で表記したときの数字の桁に含まれる穴の数の合計であるとわかった(桁の先頭に0埋めはしない)。1、2、3、5、7は穴が無く、0、4、6、9は穴が1つ、8は2つある。したがって45678は1+0+1+0+2=4となる。あなたはエリーに好印象を与えるために、ある整数から正しい答えを導くプログラムを書くことにした。整数numberが与えられたとき、その数に含まれる穴の数の合計を返せ。

public class DigitHoles {

 public int numHoles(int number) {
  int[] holes = {1, 0, 0, 0, 1, 0, 1, 0, 2, 1};
  char[] cnumber = ("" + number).toCharArray();
  int nholes = 0;
  for( int i=0 ; i<cnumber.length ; i++ ){
   nholes += holes[cnumber[i] - '0'];
  }
  return nholes;
 }

}

得点は245.00/250、1回のsubmitでシステムテストクリア。配列で穴の数を管理するのが一番簡単そうな気がします。

2014年3月2日日曜日

2014年1月の学習記録

最近ブログから離れがちなのは、仕事の煮詰まり具合によるものです。あと半年ぐらい続きそうな感がありますが、どうぞお付き合いくださいませ。

SpringによるWebアプリケーションスーパーサンプル 第2版(第1~3章)
初めて触るフレームワークなのですが、「設定より規約」ということで、どのようなルールがあるかということを理解していないと、簡単な書き方ができずに苦労しそうです。ちなみにパイロットプロジェクトとして問い合わせフォームを作り始めたのですが、参考書からちょっと外れるだけでかなり嵌っています。たとえば「戻る」ボタンを押したときにデータを保持したまま移動するという機能を実装するとか。いきなりMVCやオブジェクト指向をやっており、ショック療法を受けている真只中であります。
独習 Javaサーバサイド編 第2版(pp.1~80)
Springでの開発はjspを利用しているので、Web開発の教養と思って併読。

その他センター試験の数学を解くなど。私見ですが、今年の数学の問題は簡単な方だったと思います。

2014年1月5日日曜日

2013年12月の学習記録

久しぶりにご報告。といっても、ほとんど読めていないので、書くほどのものではないかもしれませんが。

複雑ネットワーク入門(pp.1~50)
人間関係などを解析するのに使えそう。RやPythonでグラフを描けるようなので、追々試用してみようかと。

その他、RSSのGraduate Diplomaの問題を試しに解き、TopCoderの問題を5問ほど解いた。2014年はもうちょっと勉強のペースを上げたいですねぇ。

フォロワー

ブログ アーカイブ

ページビューの合計