[ruby] 正規表現で"半角"かつ"日本語でない"かつ"スペースを含まない"を表現する

# 概要
タイトルのまま

# version

|      |       |
|:----:|:-----:|
| ruby | 2.6.3p62 (2019-04-16 revision 67580) [x86_64-linux] |
| irb  | 1.0.0 (2018-12-18) |

# 半角の正規表現

この記事を参考にしました！
[Rubyで全角半角を判定](https://konbu13.hatenablog.com/entry/2014/03/03/072330)

## 半角1文字のマッチング

上記記事によると、

- ` -~` ... ASCII
- ` -~｡-ﾟ` ... 半角文字

ということらしいので早速試してみる

```ruby
'ｱ'.match /[ -~｡-ﾟ]/
=> #<MatchData "ｱ">

'abcあいう'.match /[ -~｡-ﾟ]/
=> #<MatchData "a">
```
最初にmatchした1文字だけを検出してくれる

## 半角のみであること

```ruby
'ｱｱｱ'.match /\A[ -~｡-ﾟ]+\z/
=> #<MatchData "ｱｱｱ">

'abc'.match /\A[ -~｡-ﾟ]+\z/
=> #<MatchData "abc">

'abcあいう'.match /\A[ -~｡-ﾟ]+\z/
=> nil

'abcあいうd'.match /\A[ -~｡-ﾟ]+\z/
=> nil
```
~~正規表現の最初に `^` を、最後に `+$` をつけることで、最初から最後まで全ての文字が正規表現にmatchするかどうかを判定してくれる。~~（←間違いでした。理由は[補足](https://qiita.com/siruku6/items/7e354756a14c9a18e061#%E8%A3%9C%E8%B6%B3)を参照）
正規表現の最初に `\A` を、最後に `+\z` をつけることで、最初から最後まで全ての文字が正規表現にmatchするかどうかを判定してくれる。

## "半角のみ" かつ "日本語を含まない" こと

半角カタカナなんていらないがや。

```ruby
'ｱｱｱ'.match /\A[ -~]+\z/
=> nil

'abc'.match /\A[ -~]+\z/
=> #<MatchData "abc">

'abcあいう'.match /\A[ -~]+\z/
=> nil

'+*`{}=~<>?_)(;:@,./"\\'.match /\A[ -~]+\z/
=> #<MatchData "+*`{}=~<>?_)(;:@,./\"\\">
```
全部は試してないけど、記号も大丈夫そう。
ただ、このままだと半角スペースも許容してしまう。

```ruby
' '.match /\A[ -~]+\z/
=> #<MatchData " ">

'　'.match /\A[ -~]+\z/
=> nil
```
この通り。
この時点で全角スペースは拒否できてる。

# スペースを除外
## "半角のみ"かつ"日本語を含まない"かつ"スペースを含まない"こと

`scivola`さんのおかげで判明しましたが、[C0 Controls and Basic Latin](https://www.unicode.org/charts/PDF/U0000.pdf) によると、Unicodeの文字の順番的には以下のようになっているので、

|0020|0021|0022|0023|...|0079|007A|007B|007C|007D|007E|
|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|--:|
|半角スペース|!|"|#|....|y|z|{|&#124;|}|~|

` -~`ではなくて`!-~`にすればスペースを除外できるとのこと。
早速試してみる。

```ruby
# これだと半角スペースもマッチしてしまうが...
'abc ef'.match /\A[ -~]+\z/
=> #<MatchData "abc ef">

# ! に変えればマッチしない^^
'abc ef'.match /\A[!-~]+\z/
=> nil
```
よしよし(^ワ^)
こんな記述量で簡単に実現できるんですね。

# おまけ ~複数の正規表現で同時にチェックする~

以前、せっかく正規表現のAND演算の方法を見つけたのでここに残しておく。
ただ単に、複数の正規表現演算の結果を `&&` 演算子で繋ぐだけ。

```ruby
def half_nojapanese_nospace?(str)
  (str.match /\A[ -~]+\z/) && (str.match /\A[^[:space:]]+\z/)
end

good_str = 'abc*'
half_nojapanese_nospace?(str)
=> #<MatchData "abc*">

bad_str1 = 'abcあいう'
half_nojapanese_nospace?(str)
=> nil

bad_str2 = 'abc *+'
half_nojapanese_nospace?(str)
=> nil
```

### より良く

`match`を`match?`にすると、結果を`true`or`false`で返してくれるようにもなります^^

```ruby
def half_nojapanese_nospace?(str)
  (str.match? /\A[ -~]+\z/) && (str.match? /\A[^[:space:]]+\z/)
end

half_nojapanese_nospace?('*@abc~')
=> true

half_nojapanese_nospace?('*@abc ~')
=> false
```
こんな感じ。

# 補足

以前は理解しておらず誤った情報を記載していましたが、以下の点が間違っているようでした。
`scivola`さんご指摘ありがとうございます！

- `(文字列).match /^[正規表現の条件]+$/` ... × （← **今回の用途には使えない** ）  
理由： 文字列内に **改行文字** が含まれる場合、どれか一つの行が正規表現にマッチしさえすれば、チェックを通過してしまうため

```ruby
# 1行目 abc
# 2行目 あ
# という風に分かれてしまい、1行目の abc だけが正規表現にマッチしてしまう例
"abc\nあ".match /^[ -~｡-ﾟ]+$/
=> #<MatchData "abc">

# ただし、文字列をダブルクォートではなくシングルクォートで囲めば、
# 文字列は改行されずに1行として扱われる
'abc\nあ'.match /^[ -~｡-ﾟ]+$/
=> nil
```

- `(文字列).match /\A[正規表現の条件]\z/` ... ○  
文字列の途中に改行があったとしても、全ての行が条件に合致することをチェックしてくれる

```ruby
# ダブルクォートでもシングルクォートでも同じ結果になる^^
"abc\nあ".match /\A[ -~｡-ﾟ]+\z/
=> nil

'abc\nあ'.match /\A[ -~｡-ﾟ]+z/
=> nil
```

# 参考URL
- [【jQuery】正規表現いろいろ](https://qiita.com/konweb/items/97cccb28973aefe4b0c6)  
rubyじゃないけど、よく使われる正規表現がまとまっているので、rubyにも流用できる