動かざることバグの如し

近づきたいよ 君の理想に

PHPで文字列を1文字ずつ分割する方法が進化してた

令和最新版のPHPは一味違うぜ

概要

すごく昔に、PHPで文字列を1文字ずつの配列に変換する方法について記事を書いた。

thr3a.hatenablog.com

このときはメモ程度だったが、実は今でもそこそこPVがある。

流石に令和だしPHP7どころか8も出たしなにかアップデートあるやろ〜と冗談でドキュメント見てたら本当に進化してた。

環境

  • PHP 7.4以上

コード

ついにマルチバイト対応の関数mb_str_split()が実装された。以下のようにかける。

<?php
$str = "abcdeあい う えお";
$result = mb_str_split($str);
var_dump($result);

結果

array(12) {
  [0]=>
  string(1) "a"
  [1]=>
  string(1) "b"
  [2]=>
  string(1) "c"
  [3]=>
  string(1) "d"
  [4]=>
  string(1) "e"
  [5]=>
  string(3) "あ"
  [6]=>
  string(3) "い"
  [7]=>
  string(1) " "
  [8]=>
  string(3) "う"
  [9]=>
  string(3) " "
  [10]=>
  string(3) "え"
  [11]=>
  string(3) "お"

すげーーーーーーーー

PHP 8.0では

当然動く。が、8.0から失敗時の挙動が変わっているので注意。

この関数は、失敗時に false を返さなくなりました。

Elixir で配列をループしたいならEnum.each

Elixirで頻出する Enum.each/2 だが、書き方色々あって全然見れなかったのでメモ。

基本形

Enum.each(["one", "two", "three"], fn(x) -> IO.inspect(x) 
end)
# 出力
# "one"
# "two"
# "three"

省略記法を使う

Elixirでは無名関数を&を使って省略記法で書ける

これを使うと、 fn() -> end&() 、もっというと fn(x) -> fn2(x) end&fn2/1 と省略できるので、

Enum.each(["one", "two", "three"], &IO.inspect/1)

と書くことができる。

パイプライン演算子を使う

さらにパイプライン演算子を使うと

["one", "two", "three"] |> Enum.each(&IO.inspect/1)

と書くこともできる。

慣れるまで大変だけど数こなすしかないね。。。

Elixir マップの値を更新する方法3選

環境

  • Elixir 1.x

やりたいこと

例えば、以下のようなMapがあったとする。

user = %{name: "Taro", gender: "man", city: "Tokyo"}

ここのcityのTokyoの値を変更したり、あたらしくidのキーを追加したい。

存在するキーを更新する場合

パイプ文字を使った new_map = %{ old_map | key => value, ...} を使う。

new_user = %{user| city: "sendai"}
# => %{city: "sendai", gender: "man", name: "Taro"}

引数に続けば複数一括更新できる。

new_user = %{user | city: "sendai", name: "Ziro"}

キーが存在しなかった場合エラーになる。

iex(10)> new_user = %{user| id: 123}                         
** (KeyError) key :id not found in: %{city: "Tokyo", gender: "man", name: "Taro"}
    (stdlib) :maps.update(:id, 123, %{city: "Tokyo", gender: "man", name: "Taro"})
    (stdlib) erl_eval.erl:255: anonymous fn/2 in :erl_eval.expr/5
    (stdlib) lists.erl:1263: :lists.foldl/3

キーが存在しない場合

Map.put_new/3 を使う必要がある。

new_user = Map.put user, :id, 123
# => %{city: "Tokyo", gender: "man", id: 123, name: "Taro"}

こっちはキーが存在していても更新される。

new_user = Map.put user, :city, "sendai"
# => %{city: "sendai", gender: "man", name: "Taro"}

このように書くこともできる。

user |> Map.put(:city, "sendai")

Map.merge/2 も利用可能

Map.merge(user, %{city: "sendai"} )

じゃあキーの有無考えなくていい Map.put 全部使えばいいじゃんって話だが、本来存在しなきゃいけないときに気づけない場合もある。

ちゃんと使いどきを考えよう