日記帳

プログラミングのことをつぶやく日記です。

【PHP】特定の文字列が含まれているか調べたい

仕事で、文字列の中に、特定の文字列があるか調べる必要がありました。
正規表現を書くのも面倒だと思ってPHPマニュアルを漁っていたら、便利な’mb_strpos()’関数がありました。
簡単に’mb_strpos()’関数と、それとよく似た’mb_stripos()’関数を検証します。

mb_strpos
http://php.net/manual/ja/function.mb-strpos.php

mb_stripos
http://php.net/manual/ja/function.mb-stripos.php

mb_strpos()関数

「文字列A」の中に「文字列B」が存在するかどうか検索し、最初に見つかった位置を数値で返します。(先頭は0から始まります)
見つからなかった場合はfalseが返されます。

詳しい検証は、ソースコードを見ていきましょう。

<?php
$keyword_uppercase = 'XYZ';
$keyword_lowercase = 'xyz';

$text1 = 'abcXYZ';
$text2 = 'abcXYZabcXYZ';

// mb_strposの挙動

// 大文字は文字は含まれていると判定される
if (mb_strpos($text1, $keyword_uppercase) === false) {
    echo $keyword_uppercase . "は含まれていません" . "\n";
} else {
    echo $keyword_uppercase . "は含まれています" . "\n";
    echo mb_strpos($text1, $keyword_uppercase) . "文字目" . "\n";
}

// 小文字は含まれていないと判定される
if (mb_strpos($text1, $keyword_lowercase) === false) {
    echo $keyword_lowercase . "は含まれていません" . "\n";
} else {
    echo $keyword_lowercase . "は含まれています" . "\n";
    echo mb_strpos($text1, $keyword_lowercase) . "文字目" . "\n";
}

// 検索対象の文字列の中に、キーワードが複数含まれていても最初にマッチングした位置を返す
if (mb_strpos($text2, $keyword_uppercase) === false) {
    echo $keyword_uppercase . "は含まれていません" . "\n";
} else {
    echo $keyword_uppercase . "は含まれています" . "\n";
    echo mb_strpos($text1, $keyword_uppercase) . "文字目" . "\n";
}

実行結果

XYZは含まれています
3文字目
xyzは含まれていません
XYZは含まれています
3文字目

mb_stripos()関数

ここで不便なのが、小文字にマッチングしないことです。
SQL文の文字列をマッチングさせようとしても、
’SELECT * FROM table;’
’select * from table’
どちらも有効なクエリなため、’mb_strpos()’関数だと抜け漏れが発生します。
そこで便利なのが’mb_stripos()’関数です。
こちらは、大文字小文字の区別無しに文字列の有無を判定します。

こちらも検証のソースコードを見ていきましょう。

<?php
$keyword_uppercase = 'XYZ';
$keyword_lowercase = 'xyz';

$text1 = 'abcXYZ';

// mb_striposの挙動

// 大文字は文字は含まれていると判定される
if (mb_stripos($text1, $keyword_uppercase) === false) {
    echo $keyword_uppercase . "は含まれていません" . "\n";
} else {
    echo $keyword_uppercase . "は含まれています" . "\n";
    echo mb_stripos($text1, $keyword_uppercase) . "文字目" . "\n";
}

// 小文字も文字は含まれていると判定される
if (mb_stripos($text1, $keyword_lowercase) === false) {
    echo $keyword_lowercase . "は含まれていません" . "\n";
} else {
    echo $keyword_lowercase . "は含まれています" . "\n";
    echo mb_stripos($text1, $keyword_lowercase) . "文字目" . "\n";
}

実行結果

XYZは含まれています
3文字目
xyzは含まれています
3文字目

これだったら、大文字小文字区別なくマッチング判定できますね。

mb_strpos()関数の戻り値の誤判定

最後に’mb_strpos()’関数の誤判定について検証します。

‘mb_strpos()’関数の戻り値がfalseかどうか判定する場合、「==」演算子ではなく、必ず「===」演算子を使って判定してください。「==」演算子を使って判定した場合、0とfalseが同じ値だと判定されてしまうため、’mb_strpos()’関数が0を返した場合に誤判定が生じます。

<?php
// mbstrposの誤判定
$keyword2 = 'DEF';

$text2 = 'DEFghi';

// 含まれていないと判定される
// mb_strposの戻り値が'0'の場合、誤判定するため
// mb_strposの判定は'==='で行うこと
if (mb_strpos($text2, $keyword2) == false) {
    echo $keyword2 . "は含まれていません" . "\n";
    echo mb_strpos($text2, $keyword2) . "文字目" . "\n";
} else {
    echo $keyword2 . "は含まれています" . "\n";
}

実行結果

DEFは含まれていません
0文字目

‘DEF’は含まれているはずなのに、含まれない判定になってしまいます。

Rubyの標準入出力

Paizaのスキルチェックしていて、Rubyのファイルの入出力についてある程度の知見が溜まってきたので、まとめます。

D,Cランクの問題で迷っていたら、試してみてください。

 

入力編

ファイルからの標準入力

Paizaのページ内にエディタがあるが、大半の人は自分のPCで開発すると思います。
私は、標準入力の使用頻度は高くないので、忘れがちです。
下記のコマンドで実行すると簡単です。

p gets # 1 2 3

インプットファイル

1 2 3

ターミナルにて実行

$ ruby Main.rb < input.txt
"1 2 3"
改行マークの除去

Paizaの問題には、標準入力に改行マークがあります。
除去するにはchompメソッドを使用します。

p gets
p gets.chomp

インプットファイル

1 2 3
1 2 3
$ ruby Main.rb < input.txt
"1 2 3\n"
"1 2 3"
標準入力を整数型にして、配列に格納する。

整数型にしないと、計算処理でエラーになります。

hoge = gets.split.map(&:to_i)
p hoge
p hoge[0] + 1

fuga = gets.split
p fuga
p fuga[0] + 1

インプットファイル

1 2 3
1 2 3

ターミナルにて実行

$ ruby Main.rb < input.txt 
[1, 2, 3]
2
["1", "2", "3"]
split.rb:7:in `+': no implicit conversion of Fixnum into String (TypeError)
        fromsplit.rb:7:in `<main>'

文字列型だとエラーになります。

データ部分の読み込み

Paizaの問題で標準入力で、よくあるのは最初の1行と、2行目以降だとデータの構造が違うことがあります。
自分が2行目以降の読み込みには、よく下記のコードを書きます。

# 1行目
p gets.split.map(&:to_i)

# 2行目以降読み込み
array_of_input = []
while s = gets
  array_of_input.push(s.split.map(&:to_i))
end
p array_of_input

インプットファイル

1 2 3
2 3 4 5 6
3 4 5 6 7

ターミナルにて実行

$ ruby Main.rb < input.txt 
[1, 2, 3]
[[2, 3, 4, 5, 6], [3, 4, 5, 6, 7]]

“while s = gets”で、標準入力の最後まで読み込むまで、1行を変数”s”に代入しています。

ヘッダー部分(最初の1行目)をインスタンス変数に格納して、その後の処理で使いやすくする。

ヘッダー部分は、仕様の根幹に関わる数値で、何回も参照する必要がでてくると思います。
classを作って、インスタンス変数に格納して、インスタンスの中で呼び出せる様にしましょう。

class Hoge
    def initialize(x, y, z)
        @x = x
        @y = y
        @z = z
    end
    
    def display
        p "x: " + @x.to_s
        p "y: " + @y.to_s
        p "z: " + @z.to_s
    end
end

x, y, z = gets.split.map(&:to_i)
hoge = Hoge.new(x, y, z)
hoge.display

インプットファイル

1 2 3
2 3 4 5 6
3 4 5 6 7

ターミナルにて実行

$ ruby Main.rb < input.txt 
"x: 1"
"y: 2"
"z: 3"

出力編

レシーバのクラスを表示する

型が不一致になることが原因で、エラーになることがあります。

a = 1
b = "1"

p a + b

上記の様な単純な例だったら、すぐに解決できますが、
デバッグしてると、クラスがわからないことがあります。
そこで、classメソッドを使用します。
classメソッドは、レシーバのクラスを返します。

hoge = "ruby"
p hoge.class #=> String

p 999999999999999.class #=> Bignum
p ARGV.class #=> Array
p self.class #=> Object
p Class.class #=> Class
p Kernel.class #=> Module
2次元配列を要素ごとに連結しつつ出力

たまに2次元配列の各要素を一行づつ連結して出力しなくてはならない場面があります。
その場合は下記のように記述すれば良いでしょう。

field = [[1,2],[3,4]]
# 連結
# 12
# 34
field.each { |f| puts f.join("")}
配列のnilを削除して計算を行う

配列にnilが混ざることも多いと思います。
nilがあって一番困るのは`inject`を使う時です。
そのような場合は、`compact`を使ってnilを削除しましょう。

array = [nil, 1, 2, 3, nil]
# nilを削除して計算
p array.compact.inject(&:+) # 6

Rails初心者がもっと早く知りたかったこと

元記事は自分がQiitaであげた記事

qiita.com

Rails初心者がもっと早く知りたかったこと

スペック

・現PHPエンジニア(1年弱)

Railsエンジニア転向のため、TechAcademyのRails講座を1ヶ月受講

・現在Railsで個人開発中

・個人開発でわからないことが続出、調べながら何とか進めています。

タイムゾーン設定

APIを叩いて外部サービスの時刻を取得するのだが、日本のタイムゾーン(JST)ではなく、UTC(協定世界時)で取得するので、困った。 結論として、config/application.rbにタイムゾーンの設定を書く。

require_relative 'boot'

require "rails"
# Pick the frameworks you want:
require "active_model/railtie"
require "active_job/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "action_cable/engine"
require "sprockets/railtie"
Bundler.require(*Rails.groups)

module Typetalks
  class Application < Rails::Application
    config.time_zone = 'Tokyo'
  end
end

UTC => JSTに変換するときは、下記のよう"in_time_zone"関数を使う。

date = "2017-05-18T04:07:54Z"
p data                #2017-05-18T04:07:54Z
p data.in_time_zone   #Thu, 18 May 2017 13:07:54 JST +09:00

DBの初期化

開発環境でDBを初期化してやり直したい時がある。 そういうときは以下のコマンドを実行する。

$ rails db:reset
  1. 全てのテーブルを drop
  2. "db/schema.rb" を元にテーブルを再作成

ケースによってはmigrateファイルからテーブル作成を行いたい場合もあるだろう。 そのような場合は下記のコマンドを実行する。

$rails db:migrate:reset
  1. 全てのテーブルを drop
  2. "db/migrate/" 以下の全ての migration を実行してテーブルを再作成

requireするライブラリファイルの記述箇所

最初はcontrollerやmodelの先頭に書いていたが、何回も同じことを書くのは面倒なので、 config/initializers/stdlibs.rbで一括管理する。

require 'net/https'
require 'uri'
require 'json'
require 'time'

参考資料

RailsでDBをリセットして最初からつくり直す [俺の備忘録]

ブランチ間の差分の取り方

元記事は自分がQiitaに書いたもの

qiita.com

【git】ブランチ間の差分の取り方

ブランチ間の差分を見たい

$ git diff [ブランチ名A] [ブランチ名B]

使用例

$ git diff master develop 

ブランチAの方がBより古い扱いで差分が表示される。

リモートブランチとの比較

$ git diff origin/dvelop fix_routes

リモートブランチのdevelopとローカルのfix_routesを比較する。

更新行数を取得

$ git diff master develop --shortstat
 7 files changed, 502 insertions(+), 1 deletion(-)

オプション"--shortstat"をつけると、ブランチ間の更新行数を比較できる。

更新がかかったファイルの名前のみを表示する

--name-onlyオプションを使用する。

$ git diff --name-only