LoginSignup
0
0

More than 1 year has passed since last update.

Androidの全角/半角の正規表現には注意が必要

Posted at

結論:Androidで半角/全角区別する正規表現は[0-9][a-zA-Z0-9_]を明示的に使用しよう

端的に言うと\dを使用しても全角数字もマッチ、\wは全角英数字もマッチするよ、というお話

起こったこと

先日、業務で「インプットからの文字列に、半角数字以外が含まれている場合はバリデーションエラーを表示する」というごくごく普通の要件を満たす正規表現を書いていました。
KMMでロジックを記載しテストコードもバッチリ通っているのに、いざAndroidで試そうと全角数字を入力してところバリデーションエラーが出ない!!という状況に至りました。

もしかして、Kotlin/Native → Kotlin/JVMでの不具合か?と思って
Kolint onlineで試したところ

fun main() {
    println("全角 1 is ${isError("")}")
    println("半角 1 is ${isError("1")}")
}

fun isError(value: String): String {
    val regex = Regex("""\D+""")
    
    if (value.contains(regex)) return "Error"
    
    return "OK"
}

// Kotlin
// 全角 1 is Error
// 半角 1 is OK

// Android
// 全角 1 is OK
// 半角 1 is OK

嘘やん、、、
なんでAndroidだけ違うの、、、
ちなみにiOSではKotlinと同じく想定通りに動きました。

解決

fun main() {
    println("全角 1 is ${isError("")}")
    println("半角 1 is ${isError("1")}")
}

fun isError(value: String): String {
    val regex = Regex("""[^0-9]+""")
    
    if (value.contains(regex)) return "Error"
    
    return "OK"
}

// Kotlinも Androidも
// 全角 1 is Error
// 半角 1 is OK

冒頭にも書いたように明示的に文字クラスを使うとAndroidでも想定通りの結果になりました。

原因

結局のところあまり深く理解していないのですが

Unicodeの文字判定に依存するらしいです(小並感)
人に教えてもらうまで結構詰まってました。

メタ文字があるのに文字クラスを使用するとAndroid studioでめちゃくちゃ波線がでるけど、KDocに残してLintはsuppressしましょう!

余談

もともとInt型に変換できればええやろ!という実装がなされていたのですが、それだとそもそもKotlinで全角/半角の区別がないようです。

fun main() {
    println("全角 1 is ${isError("")}")
    println("半角 1 is ${isError("1")}")
}

fun isError(value: String): String {    
    if (value.toIntOrNull() == null) return "Error"
    
    return "OK"
}

// 全角 1 is OK
// 半角 1 is OK
0
0
0

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
0
0