旧版Android API上的PatternSyntaxException

4
我正在使用Android Studio开发一个Android应用程序,我有一个类,其中包含如下的静态属性:
public static final Pattern DIACRITICS_AND_FRIENDS = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+");

当我在我的物理设备 - API32 上调试应用程序时,一切都正常工作。
但是当我尝试在模拟器API28上调试时,每当我尝试引用“静态”类的任何静态属性时,都会出现异常。
FATAL EXCEPTION: main Process: com.example.myapp, PID: 10635
java.lang.ExceptionInInitializerError 
at com.example.myapp.MainActivity.onCreate(MainActivity.java:40)
at android.app.Activity.performCreate(Activity.java:7136) 
... 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
Caused by: java.util.regex.PatternSyntaxException: U_ILLEGAL_ARGUMENT_ERROR
[\p{InCombiningDiacriticalMarks}\p{IsLm}\p{IsSk}]+
at java.util.regex.Pattern.compileImpl(Native Method)
at java.util.regex.Pattern.compile(Pattern.java:1344)
at java.util.regex.Pattern.<init>(Pattern.java:1328)
at java.util.regex.Pattern.compile(Pattern.java:950)
at com.example.myapp.MyStaticClass.<clinit>(MyStaticClass.java:21)
... 16 more

怎么修复这个问题?
编辑:使用模拟器API30不会抛出异常,但是这行代码不再按预期工作(它不仅仅移除变音符号,而是移除了所有内容)。
str = DIACRITICS_AND_FRIENDS.matcher(str).replaceAll("")
1个回答

1
我怀疑你在正则表达式模式中使用的语法在所有 Android 版本上都不受支持。\p{} Unicode 属性转义 是 Java 正则表达式引擎的一部分,但直到 API 级别 29,它们在 Android 上才完全实现。
这意味着在低于 29 的任何 API 级别上,模式 "[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+" 会抛出 PatternSyntaxException,而在 API 级别 29 或 30 上,该模式解释不正确。
为了解决您的问题,您可以使用 Java 中的 Normalizer,它可以从字符串中去除发音符号,如 "在Java中删除重音符号和变音符号 " 中所述,由 Eugen Baeldung
然而,Normalizer 的行为也取决于 Android API 级别。以下解决方案适用于所有 Android 版本:
public static String removeDiacritics(String str) {
    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
        str = Normalizer.normalize(str, Normalizer.Form.NFKD);
        str = str.replaceAll("\\p{M}", "");
    } else {
        final Pattern DIACRITICS = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
        str = Normalizer.normalize(str, Normalizer.Form.NFD);
        str = DIACRITICS.matcher(str).replaceAll("");
    }
    return str;
}

在API 19(KITKAT)及以上版本中,使用{{link1:Normalizer.Form.NFKD}}将字符串分解为单独的字符和组合标记,然后删除所有Unicode标记(\\p{M})。对于API 19以下的版本,只删除组合变音符号Unicode块(\\p{InCombiningDiacriticalMarks}),因为这是唯一支持的Unicode属性转义。
这不会删除被归类为“字母,修饰符”(\\p{IsLm})或“符号,修饰符”(\\p{IsSk})的字符(参见示例“从Unicode字符中删除变音符号”),但不清楚您是否希望首先删除这些字符,因为您的原始代码在Android API级别低于29时会保留这些字符。
请记住,这也取决于语言:对于像德语这样的语言,您可能希望将 'ü' 转换为 'u',但重要的是要意识到对于其他语言来说,这可能是错误的。从技术上讲,上面的代码是关于去除变音符号的,但从语言学角度来看... 这是一个复杂的问题。

非常感谢!这正是我想要做的。我在API 28、30和32上进行了测试,一切都运行得非常完美! - EstevaoLuis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接