Java - \ pL [\ x00- \ x7F] + regex не может получить не английские символы, используя String.match - PullRequest
4 голосов
/ 02 июня 2019

Мне нужно проверить имя, сохраненное в строке, которое может быть на любом языке с пробелами, используя \ p {L} :

Вы можете сопоставить один символ, принадлежащий категории "буквы", с \ p {L}

Я пытался использовать String.matches, но он не соответствовал не английским символам, даже для 1 символа, например

String name = "อั";
boolean isMatch = name.matches("[\\p{L}]+")); // return false

Я пробовал с / без скобок, добавив + для нескольких букв, но он всегда не соответствует не английским символам

Есть ли проблема с использованием String.matches с \p{L}?

Мне также не удалось использовать [\\x00-\\x7F]+, предложенный в Pattern

\p{ASCII} All ASCII:[\x00-\x7F]

Ответы [ 5 ]

2 голосов
/ 02 июня 2019

Следует иметь в виду, что регулярное выражение Java анализирует строки как наборы кодов Unicode, а не кодовые точки. \p{L} соответствует любой букве Unicode из плоскости BMP, она не соответствует буквам, наклеенным после них диакритическими знаками.

Поскольку ваш ввод может содержать буквы и диакритические знаки, вы должны по крайней мере использовать классы \p{L} и \p{M} Unicode в вашем классе символов:

String regex = "[\\p{L}\\p{M}]+";

Если входная строка может содержать слова, разделенные пробелами, вы можете добавить \s сокращенный класс и для соответствия любому виду пробелов вы можете скомпилировать это регулярное выражение с флагом Pattern.UNICODE_CHARACTER_CLASS:

String regex = "(?U)[\\p{L}\\p{M}\\s]+";

Обратите внимание, что это регулярное выражение позволяет вводить диакритические знаки, буквы и пробелы в любом порядке. Если вам нужно более точное регулярное выражение (например, диакритические знаки разрешены только после базовой буквы), вы можете рассмотреть что-то вроде

String regex = "(?U)\\s*(?>\\p{L}\\p{M}*+)+(?:\\s+(?>\\p{L}\\p{M}*+)+)*\\s*";

Здесь (?>\\p{L}\\p{M}*+)+ соответствует одной или нескольким буквам, за которыми следуют ноль или более диакритических знаков, \s* соответствует нулю или нескольким пробелам, а \s+ соответствует 1 или более пробелам.

\p{IsAlphabetic} против [\p{L}\p{M}]

Если вы проверяете исходный код , \p{Alphabetic} проверяет, истинно ли Character.isAlphabetic(ch). Это верно, если символ принадлежит к одному из следующих классов: UPPERCASE_LETTER, LOWERCASE_LETTER, TITLECASE_LETTER, MODIFIER_LETTER, OTHER_LETTER, LETTER_NUMBER или имеет свойство-вкладчик Other_Alphabetic . Это является производным от Lu + Ll + Lt + Lm + Lo + Nl + Other_Alphabetic.

Хотя все эти L подклассы образуют общий класс L, обратите внимание, что Other_Alphabetic также включает Буквенный номер Nl и включает в себя больше символов, чем \p{M} class, см. эту ссылку (хотя это на немецком языке, категории и имена символов на английском).

Итак, \p{IsAlphabetic} шире, чем [\p{L}\p{M}], и вы должны принять правильное решение на основе языков, которые вы хотите поддерживать.

1 голос
/ 02 июня 2019

Попробуйте добавить больше категорий:

[\p{L}\p{Mn}\p{Mc}\p{Nl}\p{Pc}\p{Pd}\p{Po}\p{Sk}]+

Обратите внимание, что может быть лучше просто не проверять имена.Люди не могут жаловаться, если они ввели это неправильно, но ваша система не уловила это.Тем не менее, это гораздо больше проблем, если кто-то не может ввести свое имя.Если вы настаиваете на добавлении проверки, , пожалуйста, сделайте ее переопределенной: это должно иметь преимущества каждого метода без их недостатков.

1 голос
/ 02 июня 2019

Погуглил этого персонажа, чтобы найти язык.Кажется, тайский.Диапазон символов тайского Unicode: 0E00 до 0E7F :

Когда вы работаете с символами Unicode, вы можете использовать \u.Итак, регулярное выражение должно выглядеть следующим образом:

[\u0E00-\u0E7F]

Что соответствует в этом тесте REGEX вашему персонажу.

Если вы хотите сопоставить любые языки, используйтеthis:

[\p{L}]

Что соответствует этому REGEX-тесту с вашими примерами символов.

1 голос
/ 02 июня 2019

Там есть два символа. Первое - это буква, второе - это не буква.

String name = "\u0e2d";
boolean isMatch = name.matches("[\\p{L}]+"); // true

работает, но

String name = "\u0e2d\u0e31";
boolean isMatch = name.matches("[\\p{L}]+"); // false

нет, потому что 100 U + E31 - это знак без пробела [NSM], а не буква.

1 голос
/ 02 июня 2019

Единственное решение, которое я нашел, это использование \ p {IsAlphabetic}

\ p {Alpha} Буквенный символ: \ p {IsAlphabetic}

boolean isMatch = name.matches("[ \\p{IsAlphabetic}]+")) 

, который не работает на сайтах как https://regex101.com/ в демо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...