web-dev-qa-db-fra.com

Non documenté Java classe de caractères regex: \ p {C}

J'ai trouvé une expression rationnelle intéressante dans un projet Java: "[\\p{C}&&\\S]"

Je comprends que le && signifie "définir l'intersection" et \S est "non blanc", mais ce qui est \p{C}, et est-il correct d'utiliser?

La documentation Java.util.regex.Pattern ne le mentionne pas. La seule classe similaire de la liste est \p{Cntrl}, mais ils se comportent différemment: ils correspondent tous les deux aux caractères de contrôle, mais \p{C} correspond à deux fois sur les caractères Unicode au-dessus de U + FFFF, tels que 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 `????`
    }
}

La seule mention que j'ai trouvée quelque part est ici :

\ p {C} ou\p {Autre}: caractères de contrôle invisibles et points de code inutilisés.

Pourtant, \p{Other} ne semble pas exister en Java et les points de code correspondants ne sont pas inutilisés.

My Java info version:

$ 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)

Question bonus : quelle est l'intention probable du motif d'origine, "[\\p{C}&&\\S]"? Il se produit dans une méthode qui valide une chaîne avant son envoi dans un e-mail: si ce modèle est mis en correspondance, une exception avec le message "Chaîne non valide" est déclenchée.

27
doctaphred

Enfouis dans les documents Pattern sous Support Unicode, nous trouvons ce qui suit:

Cette classe est conforme au niveau 1 de Norme technique Unicode n ° 18: Expression régulière Unicode , plus les équivalents canoniques RL2.1.

...

Les catégories peuvent être spécifiées avec le préfixe facultatif Is:\p {L} et\p {IsL} désignent la catégorie des lettres Unicode. Comme pour les scripts et les blocs, les catégories peuvent également être spécifiées en utilisant le mot-clé general_category (ou sa forme courte gc) comme dans general_category = Lu ou gc = Lu.

Les catégories prises en charge sont celles de la norme Unicode dans la version spécifiée par la classe Character. Les noms de catégorie sont ceux définis dans la norme, à la fois normatifs et informatifs.

D'après Norme technique Unicode # 18 , nous constatons que C est défini pour correspondre à toute autre valeur General_Category, et que sa prise en charge fait partie des exigences de conformité au niveau 1. Java implémente \p{C} car il prétend être conforme au niveau 1 de l'UTS # 18.


Il est probablement devrait soutenir \p{Other}, mais apparemment non.

Pire, cela viole RL1.7 , requis pour la conformité de niveau 1, qui nécessite que la correspondance se fasse par point de code au lieu d'une unité de code:

Pour répondre à cette exigence, une implémentation doit gérer la gamme complète des points de code Unicode, y compris les valeurs de U + FFFF à U + 10FFFF. En particulier, lorsque UTF-16 est utilisé, une séquence composée d'un substitut de tête suivi d'un substitut de fin doit être traitée comme un seul point de code dans la correspondance.

Il ne devrait pas y avoir de correspondance pour \p{C} dans votre chaîne de test, car votre chaîne de test doit correspondre à un seul point de code emoji avec General_Category = So (Autre symbole) au lieu de deux substituts.

22
user2357112

Selon https://regex101.com/ ,\p {C} correspond

Caractères de contrôle invisibles et points de code inutilisés

(le\doit être échappé car Java, donc la chaîne \\ p {C} est regex\p {C})

Je suppose que c'est une "vérification de chaîne piratée" car un\p {C} ne devrait probablement jamais apparaître dans une chaîne valide (remplie de caractères), mais l'auteur aurait dû laisser un commentaire indiquant ce qu'il a vérifié et ce qu'il voulait vérifier sont généralement 2 choses différentes.

4
Tezra

Tout ce qui n'est pas un code de catégorie Unicode à deux lettres valide ou une seule lettre qui commence un code de catégorie Unicode est illégal car Java ne prend en charge que les abréviations à une et deux lettres pour les catégories Unicode. C'est pourquoi \p{Other} ne fonctionne pas ici.

\p{C} correspond deux fois aux caractères Unicode au-dessus de U+FFFF, comme PILE OF POO.

Droite. Java utilise le codage UTF-16 en interne pour les caractères Unicode et ???? est codé en deux unités de code 16 bits (0xD83D 0xDCA9) appelés paires de substitution ( substituts élevés ) et depuis \p{C} correspond à chaque moitié séparément

\p{Cs} ou \p{Surrogate}: la moitié d'une paire de substitution dans le codage UTF-16.

vous voyez deux correspondances dans le jeu de résultats.

Quelle est l'intention probable du modèle d'origine, [\\p{C}&&\\S]?

Je ne vois pas de raison valable, mais il semble que le développeur s'inquiète des caractères de la catégorie Other (comme éviter le spam goomojies dans le sujet de l'e-mail) alors essayez simplement de bloquer leur.

1
revo