RegEx для подмножества латинского скрипта в юникоде от XML-схемы до Java - PullRequest
0 голосов
/ 30 апреля 2019

Во-первых: я очень плохо читаю регулярные выражения и работаю со знаками Юникода.

В правительстве Германии 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));
}

Чтобы уточнить: я сохранил regEx в перечислении.Следующий метод вызывается в тестах.Как видите, он принимает только значение enum и помещает его в метод официальных совпадений.Для других регулярных выражений это прекрасно работает.

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

То, что я пробовал до сих пор:

1) Моя первая попытка состояла в том, чтобы экранировать - с помощью \-, чтобы использовать xml-schema выражает его в строке, но это все еще дает мне ложное значение в тесте только с символами и числами.

"^(([	\\-

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

2) Во-вторых, я попытался изменить регулярное выражение на предопределенный \p{isLatin}, в результатев ^\\p{isLatin}*$, но все же тест говорит, что первая строка не является допустимой латинской.

Как мне решить эту проблему?

edit: я не думаю, что это дубликат "SO Java regex для поддержки Unicode" , потому что я думаю, что моя главная проблема - понять, как я передаю выражение из xml-схемыв Яву.Тем не менее, поток помогает напомнить мне, что «начальный элемент» Юникода (\u) должен быть экранирован двойной обратной косой чертой.

1 Ответ

2 голосов
/ 30 апреля 2019

Вместо &#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\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))*

ПРИМЕЧАНИЕ: вы не можете скопировать и вставить это в строковый литерал (например, "(([\u0009-\u000a...)" из-за символов, подобных \u0009. Перед компиляцией Java преобразует все \uXXXX из исходного кода в символы, которые они представляют, таким образом, код

String str = "foo\u0009bar";

выглядит так, как будто написано

String str = "foo
bar";

, который не является допустимым Java (строки литералы не могут содержать разделители строк непосредственно в них, вместо этого они представляют их с \n и / или \r)

Но вы можете передать \u0009 в regex engine, если вы выберете \, как \\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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...