旧Android API下PatternSyntaxException异常及功能失效问题咨询
解决Android低版本正则去除变音符号的兼容性问题
问题根源
Android不同版本的正则表达式引擎对Unicode扩展属性(如\p{IsLm}、\p{IsSk}、\p{InCombiningDiacriticalMarks})支持不一致:
- API 28及以下:无法识别这些扩展属性,编译Pattern时直接抛出
PatternSyntaxException - API 30:虽能编译,但正则引擎存在匹配逻辑bug,导致执行替换时误删全部内容
- 高版本(如API32):对这些属性支持完善,因此正常工作
推荐解决方案:使用Normalizer类处理(兼容性最优)
通过Unicode规范分解的方式去除变音符号,无需依赖有兼容性问题的正则属性,API 9+即可使用:
import java.text.Normalizer; public class StringUtils { public static String removeDiacritics(String input) { if (input == null) return null; // 将字符串转换为规范分解形式(NFD),变音符号会成为独立的非间距字符 String normalized = Normalizer.normalize(input, Normalizer.Form.NFD); // 移除所有非间距标记(\p{Mn}是标准Unicode属性,全Android版本支持) return normalized.replaceAll("\\p{Mn}+", ""); } }
使用时直接调用:
str = StringUtils.removeDiacritics(str);
替代方案:兼容低版本的正则表达式
如果需要保留原正则的匹配范围(包含修饰符字母、修饰符符号),可针对不同API版本使用兼容的正则属性:
import android.os.Build; import java.util.regex.Pattern; public class MyStaticClass { public static final Pattern DIACRITICS_AND_FRIENDS; static { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) { // 高版本保留原正则 DIACRITICS_AND_FRIENDS = Pattern.compile("[\\p{InCombiningDiacriticalMarks}\\p{IsLm}\\p{IsSk}]+"); } else { // 低版本替换为标准Unicode属性:\p{Mn}替代\p{InCombiningDiacriticalMarks} DIACRITICS_AND_FRIENDS = Pattern.compile("[\\p{Mn}\\p{Lm}\\p{Sk}]+"); } } }
注:若
\p{Lm}或\p{Sk}在部分极低版本仍不支持,可进一步替换为对应的Unicode字符范围(如\u02B0-\u02FF\u037F-\u03FF...),但这种方式维护成本较高,优先推荐Normalizer方案。
内容的提问来源于stack exchange,提问作者EstevaoLuis
相关产品推荐
相关产品推荐

