LoginSignup
5
3

More than 3 years have passed since last update.

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

Last updated at Posted at 2019-07-16

概要

タイトルのまま

version

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

半角の正規表現

この記事を参考にしました!
Rubyで全角半角を判定

半角1文字のマッチング

上記記事によると、

  • -~ ... ASCII
  • -~。-゚ ... 半角文字

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

'ア'.match /[ -~。-゚]/
=> #<MatchData "ア">

'abcあいう'.match /[ -~。-゚]/
=> #<MatchData "a">

最初にmatchした1文字だけを検出してくれる

半角のみであること

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

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

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

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

正規表現の最初に ^ を、最後に +$ をつけることで、最初から最後まで全ての文字が正規表現にmatchするかどうかを判定してくれる。(←間違いでした。理由は補足を参照)
正規表現の最初に \A を、最後に +\z をつけることで、最初から最後まで全ての文字が正規表現にmatchするかどうかを判定してくれる。

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

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

'アアア'.match /\A[ -~]+\z/
=> nil

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

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

'+*`{}=~<>?_)(;:@,./"\\'.match /\A[ -~]+\z/
=> #<MatchData "+*`{}=~<>?_)(;:@,./\"\\">

全部は試してないけど、記号も大丈夫そう。
ただ、このままだと半角スペースも許容してしまう。

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

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

この通り。
この時点で全角スペースは拒否できてる。

スペースを除外

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

scivolaさんのおかげで判明しましたが、C0 Controls and Basic Latin によると、Unicodeの文字の順番的には以下のようになっているので、

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

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

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

# ! に変えればマッチしない^^
'abc ef'.match /\A[!-~]+\z/
=> nil

よしよし(^ワ^)
こんな記述量で簡単に実現できるんですね。

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

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

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

より良く

matchmatch?にすると、結果をtrueorfalseで返してくれるようにもなります^^

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 /^[正規表現の条件]+$/ ... × (← 今回の用途には使えない
    理由: 文字列内に 改行文字 が含まれる場合、どれか一つの行が正規表現にマッチしさえすれば、チェックを通過してしまうため
# 1行目 abc
# 2行目 あ
# という風に分かれてしまい、1行目の abc だけが正規表現にマッチしてしまう例
"abc\nあ".match /^[ -~。-゚]+$/
=> #<MatchData "abc">

# ただし、文字列をダブルクォートではなくシングルクォートで囲めば、
# 文字列は改行されずに1行として扱われる
'abc\nあ'.match /^[ -~。-゚]+$/
=> nil
  • (文字列).match /\A[正規表現の条件]\z/ ... ○
    文字列の途中に改行があったとしても、全ての行が条件に合致することをチェックしてくれる
# ダブルクォートでもシングルクォートでも同じ結果になる^^
"abc\nあ".match /\A[ -~。-゚]+\z/
=> nil

'abc\nあ'.match /\A[ -~。-゚]+z/
=> nil

参考URL

5
3
4

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3