ツナでもわかるmruby [2回目：文字列]


![ツナ2.jpg](https://qiita-image-store.s3.amazonaws.com/0/13835/903221f8-ba2f-f02f-30b1-11a346c0cc11.jpeg "ツナ2.jpg")

[1回目](http://qiita.com/hiroeorz@github/items/112e5bfbb3ff4d9486bc)で定番のHello Worldやったので、今回からは基本となる組込みの型を幾つか、さらっと学びます。
写真は我が家の猫、ツナです。mrubyとは特に関係がありません。

以下は全て、mrubyに含まれる対話型のRubyシェルmirbから直接試す事ができます。

```
$ mirb
mirb  Embeddable Interactive Ruby Shell

>
```

## 文字列
[Rubyリファレンス](http://docs.ruby-lang.org/ja/1.9.3/class/String.html#I_--25)のStringクラスを参照しながらよく使うものを試します。

なお、僕の環境ではmrubyコンパイル時に<code>build_config.rb</code>

```ruby:build_config.rb
conf.gembox 'full-core'
```

を指定したのでmrbgemsの<code>mruby-string-ext</code>で提供されているメソッドも含まれます。
デフォルトの

```ruby:build_config.rb
conf.gembox 'default'
```

でも同様に<code>mruby-string-ext</code>が組込まれます。

####文字列の連結

```ruby:mirb
"aaa" + "bbb" #=> "aaabbb"
```

####文字列の繰り返し

```ruby:mirb
"abc" * 3 #=> "abcabcabc"
```

####破壊的連結

```ruby:mirb
"aaa" << "bbb"      #=> "aaabbb"
"aaa".concat("bbb") #=> "aaabbb"
```
<code>"aaa" + "bbb"</code>は新しいオブジェクトを生成するけど<code><<</code>,<code>concat</code>は元のオブジェクトを破壊的に変更するので速い、けど使い方を間違えるとバグの原因にもなるというのは多分Rubyと同じ。

####比較

```ruby:mirb
"aaa" == "bbb" #=> false
"aaa" == "aaa" #=> true
```

####正規表現

```ruby:mirb
"hello world" =~ /world/
(mirb):8: uninitialized constant Regexp (NameError)
```
おっと...？ 正規表現はないのかな...？でもRegexpクラスのインスタンス自体は生成しようとしているっぽい。なんだろ？と思ってググってみたらわかりました。
[mruby から正規表現が消え、正規表現がやってきた。](http://mattn.kaoriya.net/software/lang/ruby/20130221172829.htm)

内容から読み取れる事は、mruby自体は正規表現の機能は提供しない。ただしユーザー側で正規表現を扱う為のRegexpクラスを用意した場合に、それをStringクラスのインスタンスから呼び出すようにはしておくよって事のようです。なので今回は正規表現はスキップ。また改めて試します。

####指定位置の文字の取得

```ruby:mirb
"abced"[0] #=> "a"
"abced"[1] #=> "b"
"abced"[2] #=> "c"
```

負の値を指定すると最後から左方向に数えた位置の文字

```ruby:mirb
"abced"[-1] #=> "d"
"abced"[-2] #=> "e"
```

####指定位置からの指定長さ分の文字列を取得

```ruby:mirb
"abced"[0, 2] #=> "ab"
```

####指定範囲の文字列を取得

```ruby:mirb
"abced"[1..3] #=> "bce"
```

####文字数の取得

```ruby:mirb
"abced".size #=> 5
```

日本語UTF8も1文字は1文字。

```ruby:mirb
"こんにちわ".size #=> 5
```

####バイト数の取得

```ruby:mirb
"abced".bytesize #=> 5
```

日本語UTF8では文字数ではなくてバイト数を返す。

```ruby:mirb
"こんにちわ".bytesize #=> 15
```

####末尾の改行を削除

```ruby:mirb
"abc\n".chomp   #=> "abc"
"abc\r\n".chomp #=> "abc"
```

破壊的メソッド。もとの文字列オブジェクトを変更する為、速いが使い方によってはバグの原因になり易い。

```ruby:mirb
"abc\n".chomp!   #=> "abc"
"abc\r\n".chomp! #=> "abc"
```

####部分文字列の置換

```ruby:mirb
"Hello World".gsub("World", "Japan")  #=> "Hello Japan"
"Hello World".gsub!("World", "Japan") #=> "Hello Japan" 破壊的
```

第一引数が文字列の場合はいずれも問題なく置換できました。

```ruby:mirb
"Hello World".gsub(/World/, "Japan")
(mirb):34: uninitialized constant Regexp (NameError)
```

正規表現での指定はやはりエラーです。Regexpクラスを別途用意すれば動作すると思われます。

####文字列を16進数として解釈

```ruby:mirb
"ab".hex   #=> 171
"ff".hex   #=> 255
"ffff".hex #=> 65535
```

####文字列からシンボルを生成

```ruby:mirb
"abc".to_sym #=> :abc
```

####左右逆転

```ruby:mirb
"abc".reverse  #=> "cba"
"abc".reverse! #=> "cba" 破壊的
```

####指定文字で分割して配列にする

```ruby:mirb
"aaa,bbb,ccc,ddd".split(",") #=> ["aaa", "bbb", "ccc", "ddd"]
```

分割文字はデフォルトで<code>,</code>なので省略しても結果は同じ

```ruby:mirb
"aaa,bbb,ccc,ddd".split #=> ["aaa", "bbb", "ccc", "ddd"]
```

例によって正規表現での指定はRegexpクラスを用意していなければエラー。

```ruby:mirb
"aaa,bbb,ccc,ddd".split(/,/)
(mirb):50: uninitialized constant Regexp (NameError)
```

Ruby同様、mrubyも文字列関係充実しまくってて、きりがないのでここまでで...
[Rubyのリファレンスマニュアル](http://docs.ruby-lang.org/ja/1.9.3/class/String.html)にあるものは多くが動くようですが、cryptなど動作しないものもありますので注意が必要です。

## mrubyで正規表現を使えるようにする
組込み向けのmrubyで正規表現がどうしても必要な場面がどの程度有るかはわかりませんが、最初に書いたような理由でmrubyはデフォルトでは正規表現が使えないようです。ただ、Regexpクラスを用意すればmruby側からはそれを呼んでくれるようになっているようで、たとえば、この[mattn/mruby-onig-regexp](https://github.com/mattn/mruby-onig-regexp)のようなライブラリを使わせてもらえば、Rubyと同じように正規表現が使えるようになります。

### mruby-onig-regexpを組込んでmrubyを再コンパイル
[README.md](https://github.com/mattn/mruby-onig-regexp/blob/master/README.md)に使い方が書いてあります。

mruby-onig-regexpを使うにはmrubyを再度コンパイルする必要が有りますので。<code>build_config.rb</code>に以下を追加して

```ruby:build_config.rb
conf.gem :github => 'mattn/mruby-onig-regexp'
```

rakeします。

```
$ rake
```

###インストール
できたバイナリを必要に応じてパスの通った場所にコピーします。

```
$ sudo cp bin/* /usr/local/mruby/bin/
```

###動作確認
これで、この投稿の前半でエラーが出ていたコードは全て実行できるようになります。

```ruby:mirb
"hello world" =~ /world/ #=> 6
```

```ruby:mirb
"Hello World".gsub(/World/, "Japan") #=> "Hello Japan"
```

よいですね。

```ruby:mirb
"aaa,bbb,ccc,ddd".split(/,/)
(mirb):12: Regexp class not implemented (NotImplementedError)
```
oh...why?
ちょっとコード読んでみよう...