有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

从xmlschema到java的unicode拉丁脚本子集的正则表达式

第一:我非常不擅长阅读正则表达式和处理unicode符号

在德国政府,IT系统不能支持所有字符,只能支持Latin_script_in_Unicode的子集

在官方文档中,为XML模式提供了以下正则表达式:

(([	-

 -~¡-¬®-ćĊ-ěĞ-ģĦ-ıĴ-śŞ-ūŮ-žƏƠ-ơƯ-ưƷǍ-ǔǞ-ǟǤ-ǰǴ-ǵǺ-ǿȘ-țȞ-ȟȪ-ȫȮ-ȳəʒḂ-ḃḊ-ḋḐ-ḑḞ-ḡḤ-ḧḰ-ḱṀ-ṁṄ-ṅṖ-ṗṠ-ṣṪ-ṫẀ-ẅẌ-ẓẞẠ-ầẪ-ẬẮ-ềỄ-ồỖ-ờỤ-ỹ€])|(M̂|N̂|m̂|n̂|D̂|d̂|J̌|L̂|l̂))*

我现在正试图将这个正则表达式迁移到Java,我想知道如何做到这一点。在我的第一步中,我编写了这两种测试方法,它们显然是有效的拉丁字符串,或者显然不是:

@Test
@DisplayName("OK: Just normal characters and numbers")
void testJustNormalCharacters() {
  String sut = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";

  assertTrue(RegExPruefung.matches(sut, RegEx.T_VALIDSTRINGLATIN));
}

@Test
@DisplayName("NOK: Chinese sign")
void testChineseSign() {
  String sut = "abc⺠";

  assertFalse(RegExPruefung.matches(sut, RegEx.T_VALIDSTRINGLATIN));
}

澄清一下:我在枚举中保存了正则表达式。在测试中调用以下方法。如您所见,它只接受枚举值并将其放入Official matches方法中。对于其他正则表达式,这很好

public static boolean matches(String stringToCheck, RegEx regExToMatch) {
  return stringToCheck.matches(regExToMatch.getRegEx());
}    

到目前为止,我所尝试的:

1)我的第一次尝试是使用\-来转义-,以使用xml模式表达式,并在字符串中使用它,但这仍然给了我一个只有字符和数字的测试错误

"^(([	\\-

 \\-~¡\\-¬®\\-ćĊ\\-ěĞ\\-ģĦ\\-ıĴ\\-śŞ\\-ūŮ\\-žƏƠ\\-ơƯ\\-ưƷǍ\\-ǔǞ\\-ǟǤ\\-ǰǴ\\-ǵǺ\\-ǿȘ\\-țȞ\\-ȟȪ\\-ȫȮ\\-ȳəʒḂ\\-ḃḊ\\-ḋḐ\\-ḑḞ\\-ḡḤ\\-ḧḰ\\-ḱṀ\\-ṁṄ\\-ṅṖ\\-ṗṠ\\-ṣṪ\\-ṫẀ\\-ẅẌ\\-ẓẞẠ\\-ầẪ\\-ẬẮ\\-ềỄ\\-ồỖ\\-ờỤ\\-ỹ€])|(M̂|N̂|m̂|n̂|D̂|d̂|J̌|L̂|l̂))*$"

2)其次,我尝试将正则表达式更改为预定义的\p{isLatin},结果是^\\p{isLatin}*$,但测试仍然表明第一个字符串不是有效的拉丁字符串

我如何解决这个问题

编辑: 我不认为它是"SO Java regex for support Unicode"的副本,因为我认为我的主要问题是理解如何将表达式从xml模式转换到java。尽管如此,该线程还是提醒我,unicode“start element”(\u)必须用双反斜杠转义


共 (1) 个答案

  1. # 1 楼答案

    你需要的不是&#xHEX;,而是\uHEX。注意,虽然&#xHEX;;表示序列的结尾,但\uHEX没有;,而是始终有4个十六进制值,可能有前导零

    所以	不是表示为\u9,而是表示为\u0009

    无论如何,您可以创建regex工具来动态替换它们

    String originalRegex = "(([	-

 -~¡-¬®-ćĊ-ěĞ-ģĦ-ıĴ-śŞ-ūŮ-žƏƠ-ơƯ-ưƷǍ-ǔǞ-ǟǤ-ǰǴ-ǵǺ-ǿȘ-țȞ-ȟȪ-ȫȮ-ȳəʒḂ-ḃḊ-ḋḐ-ḑḞ-ḡḤ-ḧḰ-ḱṀ-ṁṄ-ṅṖ-ṗṠ-ṣṪ-ṫẀ-ẅẌ-ẓẞẠ-ầẪ-ẬẮ-ềỄ-ồỖ-ờỤ-ỹ€])|(M̂|N̂|m̂|n̂|D̂|d̂|J̌|L̂|l̂))*";
    
    Pattern p = Pattern.compile("&#x(?<hex>[0-9a-z]{1,4});", Pattern.CASE_INSENSITIVE);
    Matcher m = p.matcher(originalRegex);
    
    StringBuffer sb = new StringBuffer();
    while(m.find()){
        int decValue = Integer.parseInt(m.group("hex"), 16);
        String replacement = String.format("\\u%04x", decValue);
        m.appendReplacement(sb, Matcher.quoteReplacement(replacement)); // quoteReplacement to escape "\"
    }
    m.appendTail(sb);
    String replacedRegex = sb.toString();
    //System.out.println(replacedRegex);
    

    这给了我们{}

    注意:您不能将其复制粘贴到字符串文字(如"(([\u0009-\u000a...)"),因为有\u0009这样的字符。在编译之前,Java会将源代码中的所有\uXXXX转换为它们所表示的类似于代码的字符

    String str = "foo\u0009bar";
    

    看起来好像是这样写的

    String str = "foo
    bar";
    

    这是无效的Java(字符串文本不能直接包含行分隔符,而是\n和/或\r表示

    但是,例如,如果像\\u0009一样转义\,则可以将\u0009传递给正则表达式引擎

    String replacedRegex = "(([\\u0009-\\u000a\\u000d\\u0020-\\u007e\\u00a1-\\u00ac\\u00ae-\\u0107\\u010a-\\u011b\\u011e-\\u0123\\u0126-\\u0131\\u0134-\\u015b\\u015e-\\u016b\\u016e-\\u017e\\u018f\\u01a0-\\u01a1\\u01af-\\u01b0\\u01b7\\u01cd-\\u01d4\\u01de-\\u01df\\u01e4-\\u01f0\\u01f4-\\u01f5\\u01fa-\\u01ff\\u0218-\\u021b\\u021e-\\u021f\\u022a-\\u022b\\u022e-\\u0233\\u0259\\u0292\\u1e02-\\u1e03\\u1e0a-\\u1e0b\\u1e10-\\u1e11\\u1e1e-\\u1e21\\u1e24-\\u1e27\\u1e30-\\u1e31\\u1e40-\\u1e41\\u1e44-\\u1e45\\u1e56-\\u1e57\\u1e60-\\u1e63\\u1e6a-\\u1e6b\\u1e80-\\u1e85\\u1e8c-\\u1e93\\u1e9e\\u1ea0-\\u1ea7\\u1eaa-\\u1eac\\u1eae-\\u1ec1\\u1ec4-\\u1ed3\\u1ed6-\\u1edd\\u1ee4-\\u1ef9\\u20ac])|(\\u004d\\u0302|\\u004e\\u0302|\\u006d\\u0302|\\u006e\\u0302|\\u0044\\u0302|\\u0064\\u0302|\\u004a\\u030c|\\u004c\\u0302|\\u006c\\u0302))*";
    

    现在让我们测试正则表达式是否按预期工作:

    Pattern RegExPruefung = Pattern.compile(replacedRegex);
    
    String sut = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
    System.out.println(RegExPruefung.matcher(sut).matches());
    sut = "abc⺠";
    System.out.println(RegExPruefung.matcher(sut).matches());
    

    输出:

    true
    false