Подтвердить что ты не робот

Недокументированный класс символов регулярного выражения Java:\p {C}

Я нашел интересное регулярное выражение в проекте Java: "[\\p{C}&&\\S]"

Я понимаю, что && означает "установить пересечение", а \S - "не-whitespace", но что такое \p{C}, и можно ли использовать?

java.util.regex.Pattern documentation не упоминает об этом. Единственный подобный класс в списке - \p{Cntrl}, но они ведут себя по-разному: оба они совпадают с управляющими символами, но \p{C} совпадает дважды с символами Юникода выше U + FFFF, например PILE OF POO:

public class StrangePattern {
    public static void main(String[] argv) {

        // As far as I can tell, this is the simplest way to create a String
        // with code points above U+FFFF.
        String poo = new String(Character.toChars(0x1F4A9));

        System.out.println(poo);  // prints `💩`
        System.out.println(poo.replaceAll("\\p{C}", "?"));  // prints `??`
        System.out.println(poo.replaceAll("\\p{Cntrl}", "?"));  // prints `💩`
    }
}

Единственное упоминание, которое я нашел где-то, здесь:

\ p {C} или \p {Other}: невидимые управляющие символы и неиспользуемые кодовые точки.

Однако \p{Other}, похоже, не существует в Java, а совпадающие кодовые точки не используются.

Информация о моей версии Java:

$ java -version
java version "1.8.0_92"
Java(TM) SE Runtime Environment (build 1.8.0_92-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.92-b14, mixed mode)

Бонусный вопрос: каково вероятное намерение исходного шаблона, "[\\p{C}&&\\S]"? Это происходит в методе, который проверяет строку перед ее отправкой по электронной почте: если этот шаблон сопоставляется, возникает исключение с сообщением "Неверная строка".

4b9b3361

Ответ 1

Погруженный в паттерны документов под поддержкой Unicode, мы находим следующее:

Этот класс находится в соответствии с уровнем 1 Unicode Technical Standard # 18: Unicode Regular Expression, а также канонические эквиваленты RL2.1.

...

Категории могут быть указаны с дополнительным префиксом Is: Both\p {L} и \p {IsL} обозначают категорию букв Unicode. То же, что и скрипты и блоки, категории также можно указать, используя ключевое слово general_category (или его короткая форма gc), как в general_category = Lu или дс = Л.

Поддерживаемые категории - это категории стандарта Unicode в версии, указанной классом Character. Названия категорий - это те определенных в Стандарте, как нормативных, так и информативных.

Из Unicode Technical Standard # 18, мы обнаруживаем, что C определено в соответствии с любым другим значением General_Category, и эта поддержка для этого часть требований для соответствия уровня 1. Java реализует \p{C}, потому что утверждает, что соответствует уровню 1 UTS # 18.


Вероятно, он должен поддерживать \p{Other}, но, видимо, этого не делает.

Хуже того, что он нарушает RL1.7, необходимый для соответствия уровня 1, который требует, чтобы соответствие выполнялось по кодовой точке вместо единицы кода:

Для удовлетворения этого требования реализация должна обрабатывать полный диапазон кодовых точек Юникода, включая значения от U + FFFF до U + 10FFFF. В частности, где используется UTF-16, последовательность, состоящая из ведущего суррогата, за которым следует завершающий суррогат, должна обрабатываться как единая кодовая точка при сопоставлении.

В тестовой строке не должно быть совпадений для \p{C}, потому что ваша тестовая строка должна быть сопоставлена ​​как одна кодовая точка emoji с General_Category = So (другой символ) вместо двух суррогатов.

Ответ 2

Согласно https://regex101.com/,\p {C} соответствует

Невидимые управляющие символы и неиспользуемые кодовые точки

(\ должен быть экранирован, потому что строка java, поэтому строка \\p {C} является регулярным выражением \p {C})

Я предполагаю, что это "взломанная проверка строки", поскольку \p {C}, вероятно, никогда не должен появляться внутри допустимой (заполненной символом) строки, но автор должен оставить комментарий как то, что они проверили, и что они хотели проверить, как правило, две разные вещи.

Ответ 3

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

\p{C} дважды совпадает с символами Unicode выше U+FFFF, такими как PILE OF POO.

Right. Java использует внутреннюю кодировку UTF-16 для символов Unicode, а 💩 кодируется как два 16-разрядных кодовых блока (0xD83D 0xDCA9), называемых суррогатными парами (высокие суррогаты), а так как \p{C} соответствует каждой половине отдельно

\p{Cs} или \p{Surrogate}: одна половина суррогатной пары в UTF-16 кодирование.

вы видите два совпадения в наборе результатов.

Каково вероятное намерение исходного шаблона, [\\p{C}&&\\S]?

Я не вижу достаточно веской причины, но, похоже, разработчик обеспокоен персонажами в категории Other (например, избегая спама goomojies в теме письма), поэтому просто попытался заблокировать их.