IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage PHP Discussion :

REGEX "simple" champ prénom


Sujet :

Langage PHP

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut REGEX "simple" champ prénom
    Bonjour,

    Pourriez-vous, svp, me venir en aide.
    J'ai du mal à comprendre pourquoi ma Regex ne fonctionne pas, et cela depuis bien trop de tps, elle est pourtant simple;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    $pattern = "#^[A-ZÇÉÈÊËÀÂÎÏÔÙÛ]{1}[a-zçéèêëàâîïôùû]+[-]?[a-zçéèêëàâîïôùû]*#";
     
    if (preg_match($pattern,$prenom_post)) 
       {//Vrai je traite
       }
    else
       {//Erreur -> message d'erreur
       $erreur='Le champ Prénom contient des caractères non autorisés';
       }
    Explication du résulta attendu :
    ^[A-ZÇÉÈÊËÀÂÎÏÔÙÛ]{1} : Commence pas une lettre majuscule accentuée (liste) ou non
    [a-zçéèêëàâîïôùû]+ : Puis est suivi d'une ou plusieurs lettre(s) minuscule(s) accentuée (liste) ou non
    [-]? : Puis de 0 ou un tiret
    [a-zçéèêëàâîïôùû]* : et enfin d'aucune ou plusieurs lettre(s) minuscule(s) accentuée (liste) ou non

    Je vous remercie et reste impatiemment dans l'attente de vous lire,
    Bien Cdlmt.

    Kiiiint13

  2. #2
    Modératrice
    Avatar de Celira
    Femme Profil pro
    Développeuse PHP/Java
    Inscrit en
    Avril 2007
    Messages
    8 633
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Développeuse PHP/Java
    Secteur : Industrie

    Informations forums :
    Inscription : Avril 2007
    Messages : 8 633
    Points : 16 372
    Points
    16 372
    Par défaut
    A priori, ta regex est Ok. En passant par PHP Live Regex, Jean-claude passe, Celira aussi, Stéphane pareil. Zorg42 ne passe pas, chaussette non plus.
    Tu devrais peut-être vérifier ce qui arrive dans $prenom_post (genre via un var_dump)

    Au passage, dans un prénom composé, il y a normalement une majuscule à chaque élément.
    Modératrice PHP
    Aucun navigateur ne propose d'extension boule-de-cristal : postez votre code et vos messages d'erreurs. (Rappel : "ça ne marche pas" n'est pas un message d'erreur)
    Cherchez un peu avant poser votre question : Cours et Tutoriels PHP - FAQ PHP - PDO une soupe et au lit !.

    Affichez votre code en couleurs : [CODE=php][/CODE] (bouton # de l'éditeur) et [C=php][/C]

  3. #3
    Membre émérite Avatar de Djakisback
    Profil pro
    Inscrit en
    Février 2005
    Messages
    2 021
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Février 2005
    Messages : 2 021
    Points : 2 278
    Points
    2 278
    Par défaut
    Salut,
    perso je comprends pas bien ta description sur le dernier match :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    [a-zçéèêëàâîïôùû]* : et enfin d'aucune ou plusieurs lettre(s) minuscule(s) accentuée (liste) ou non
    tu veux dire "et enfin d'aucune ou plusieurs lettres Majuscules accentuées" ?
    si tu veux coller à ta description c'est : [^a-zçéèêëàâîïôùû]*
    pour la classe inverse à matcher a priori.
    Avec les REGEX un exemple à matcher est toujours plus simple pour l'analyse, si t'en as à fournir ?
    Vive les roues en pierre

  4. #4
    Invité
    Invité(e)
    Par défaut
    Bonjour,

    1/ Je ne vois pas trop l’intérêt de vérifier un prénom, surtout à notre époque, où on met n'importe quoi. (à lire : pires prénoms 2014 ! )

    2/ Personnellement, ta regex va me rapidement gonfler : je veux pouvoir écrire mon prénom tout en minuscules ou tout en majuscules, avec ou sans accents si je veux !
    (surtout si j'écris sur mon smartphone !)
    Mon prénom ? Jérôme Gaëtan !! (autant dire que je me sens concerné !)

    3/ Si la seule chose que tu souhaites vérifier est "uniquement des caractères autorisés" :
    • alpha, majuscule ou minuscule + lettres accentués
    • espace, tiret, apostrophe

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #^([a-zàáâäçèéêëìíîïñòóôöùúûü \-\']+)$#Ui
    [EDIT] Je me rend compte dans mes essais qu'une majuscule accentuée ne passe pas ! (cas de "Éléa-Maud" ci-après)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    #^([a-zA-ZàáâäæçéèêëîïôœùûüÿÀÂÄÆÇÉÈÊËÎÏÔŒÙÛÜŸ \-\']+)$#Ui
    Quelques prénoms :
    Méloîe
    Éléa-Maud
    Maëlys
    jean-rené la Taupe
    Léo-andréa
    Rock's-Ann
    4/ Enfin, si tu veux ENSUITE mettre des majuscules aux initiales (pour enregistrement en BdD, par exemple) :
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    $prenom = mb_convert_case ( $prenom,  MB_CASE_TITLE );
    Dernière modification par Invité ; 07/11/2015 à 08h53.

  5. #5
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut REGEX "simple" champ prénom
    Bonjour à tous,
    Merci pour vos réponses réactives et pour vos remarques constructives et pertinentes.

    @ Djakisback
    Non je voulais bien dire des « d'aucune ou plusieurs lettre(s) minuscule(s) accentuée (liste) ou non », dans l’objectif de prendre en charge les prénoms composés.

    @ Celira
    Merci, I’m crazy… désolé. Néanmoins ta remarque est très pertinente et m’a fait évoluer ma regex, voir ci-dessous.

    @ jreaux62
    Merci beaucoup pour ces remarques toutes aussi pertinentes ;

    1/Cela va vraiment dépendre du secteur d’activité, un forum pour jeux vidéos ou une interface web bancaire par exemple… tu me le concéderas je pense…

    2/Carrément !! Peut importe le type de site cela est gonflant !! A quand le cas passant surtout s’il y a plusieurs champs et un contrôle si poussé comme est mon cas.
    Pour palier ça je « nettoie » mes variables des erreurs de frappe/forme avant d’appliquer mes regex.
    De telle manière que la variable est automatiquement mise en minuscule avec une majuscule à la première lettre du prénom (et aussi cas du prénom composé, maintenant…), puis les lettres répétées et les espaces sont supprimés.
    Enfin, seulement j’applique ma regex..

    3/ Pblm laisse passer plusieurs tirets…

    4/Oui c’est ce que je fais avant d’appliquer ma regex.



    Voiçi donc la V2 de ma regex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	$regex_1 ="#^[A-ZÇÉÈÊËÀÂÎÏÔÙÛ]{1}([a-zçéèêëàâîïôùû]+|([a-zçéèêëàâîïôùû]+-[A-ZÇÉÈÊËÀÂÎÏÔÙÛ]{1}[a-zçéèêëàâîïôùû]+)){1,19}$#";
    Littéralement :
    Commencer par une lettre majuscule (accentuées ou non), puis collé à (et finir part..)
    [cas prénom simple] Soit de une à 19 lettres minuscules (accentuées ou non)
    OU
    [cas prénom composé] Soit de une à plusieurs lettres minuscules (accentuées ou non), puis d’un tiret et d’une lettre majuscule (accentuées ou non) et enfin de une à plusieurs lettres minuscules (accentuées ou non). 19 lettres au maximum

    Le champ accepte donc entre 2 et 20 caractères.

  6. #6
    Invité
    Invité(e)
    Par défaut
    Alors, si j'écris JEROME ou jerome, ça ne passe pas.

    Je confirme : ça va me gonfler...

    Quant au nombre de caracteres :
    http://www.linternaute.com/savoir/ma...us-longs.shtml


    Et dans "Le 5ème élément" : Leeloo, de son nom complet Leeloominai Lekatariba Laminatchai Ekbat De Sebat !
    Dernière modification par Invité ; 08/11/2015 à 12h15.

  7. #7
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Ne cherche pas à tout faire d'un coup de pattern.
    Part du principe que la casse n'a aucune importance (de toute manière c'est quasi impossible de vérifier si la casse est correcte avec des prénoms tordus où il n'y a pas forcément de majuscule après un tiret ou une apostrophe). Donc ça c'est réglé, tu colles le flag i à ta pattern pour qu'elle soit case-insensitive.

    Ensuite comme les lettres accentuées sont autorisées tu vas devoir utiliser un autre flag qui permet au moteur de regex de lire correctement une chaîne de caractères avec des caractères codés en UTF8, le flag u. En UTF8 un caractère en dehors de la plage ASCII est codé sur plusieurs octets (par exemple "c3 a2" pour le "â"), mais par défaut le moteur de regex considère que chaque octet est un caractère et il ne fait pas le lien entre plusieurs octets (donc un caractère "c3" et un caractère "a2"). Avec le flag u les caractères multibytes sont correctement identifiés.

    Quel set de lettres accentuées choisir? Je te conseille d'être large et de ne pas te limiter aux lettres accentuées du français. Désormais, les caractères non français sont autorisés à l'état civil (donc sur une carte d'identité française tu peux très bien trouver un prénom avec un ñ, un ž ou autre). Dans ce cas au lieu d'énumérer tous les caractères accentués possibles et imaginable, autant utiliser la classe de caractère \p{Latin} qui les contient tous (y compris les non-accentués). Du coup si tu utilises cette classe, tu peux enlever le flag i.

    Maintenant en ce qui concerne les tirets, les espaces, les simple quotes (guillemet simple utilisé couramment à la place de l'apostrophe), les apostrophes et une éventuelle "correction automatique". Ce n'est pas forcément une question facile:
    • Pour ce qui est d'un espace au début, à la fin, à coté d'un tiret, avant un quote ou apostrophe, de plusieurs espaces consécutifs, ou de deux tirets, apostrophes ou quotes qui se suivent, on enlève (ce sont des fautes de frappe il n'y a pas photo et on peut les traiter automatiquement):
      Code : Sélectionner tout - Visualiser dans une fenêtre à part
      $prenom = preg_replace("~^[-’' ]+|[- ]+$| +(?=['’-])| \K +|-\K(?: +|-+)|’\K’+|'\K'+~uS", '', $prenom);
      et c'est torché.
    • Par contre pour ce qui est du quote ou de l'apostrophe, là ça se complique, parce qu'ils peuvent être entre deux mots (avec la même fonction qu'un trait d'union) mais aussi à la fin d'un mot (un accent aigu archaïque: É => E’) et dans ce dernier cas il est tout à fait possible d'être en fin de chaîne ou d'avoir un espace et un autre mot après. Il faut donc accepter ces cas de figure.


    Pour ce qui est de la taille de la chaîne, le plus simple reste de la vérifier à part.

    Donc au final je ferais un truc de ce genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    if (isset($_POST['prenom'])) {
        $prenom = preg_replace("~^[-’' ]+|[- ]+$| +(?=['’-])| \K +|-\K(?: +|-+)|’\K’+|'\K'+~uS", '', $_POST['prenom']);
        if (mb_strlen($prenom) <= FORNAME_MAX_SIZE && preg_match("~^\p{Latin}+(?:(?:[- ]|['’] ?)\p{Latin}+)*['’]?$~u", $prenom)) {
            // ensuite soit on le stocke tel quel, soit on le stocke en le passant en uppercase ou en lowercase.
        }
    }
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  8. #8
    Membre confirmé Avatar de 01001111
    Homme Profil pro
    Développeur Web
    Inscrit en
    Janvier 2009
    Messages
    319
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Loire (Auvergne)

    Informations professionnelles :
    Activité : Développeur Web
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Janvier 2009
    Messages : 319
    Points : 509
    Points
    509
    Par défaut
    CosmoKnacki s'en mèle. Très belle regexp, monsieur!

    De mon côté, je te proposerais d'utiliser une double entrée en base de données... un entrée avec des caractères sans diacritiques, qui devrait être testée non vide pour permettre l'insertion, de l'autre la chaine originale, nettoyée de certains caractères.

    comme ça tu te retrouves avec deux chaines, une pour la réalité, une plus simple pour la manipulation numérique.
    tu peux éventuellement aussi modifier la fonction suivante pour supprimer de la chaine originale les caractères qui ne correspondraient pas au groupe /[a-z]/i plus les caractères avec diacritiques, plus quelques caractères que tu autoriserais genre les apostrophes les tirets etc...

    voici la fonction que j'ai adaptée d'un proposition javascript sur un autre forum:
    Code php : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
     
    function removeDiacritics($string) {
    	$string=trim($string);
    	$diacriticsEquivalent=array(
    		0xc3 => array(
    			0xc380 => 'A', 0xc381 => 'A', 0xc382 => 'A', 0xc383 => 'A', 0xc384 => 'A', 0xc385 => 'A', 0xc386 => 'AE', 0xc387 => 'C', 
    			0xc388 => 'E', 0xc389 => 'E', 0xc38a => 'E', 0xc38b => 'E', 0xc38c => 'I', 0xc38d => 'I', 0xc38e => 'I', 0xc38f => 'I', 
    			0xc390 => 'D', 0xc391 => 'N', 0xc392 => 'O', 0xc393 => 'O', 0xc394 => 'O', 0xc395 => 'O', 0xc396 => 'O', 0xc398 => 'O', 
    			0xc399=> 'U', 0xc39a => 'U', 0xc39b => 'U', 0xc39c => 'U', 0xc39d => 'Y', 0xc39f => 'S', 0xc3a0 => 'a', 0xc3a1 => 'a', 
    			0xc3a2 => 'a', 0xc3a3 => 'a', 0xc3a4 => 'a', 0xc3a5 => 'a', 0xc3a6 => 'ae', 0xc3a7 => 'c', 0xc3a8 => 'e', 0xc3a9 => 'e', 
    			0xc3aa => 'e', 0xc3ab => 'e', 0xc3ac => 'i', 0xc3ad => 'i', 0xc3ae => 'i', 0xc3af => 'i', 0xc3b0 => 'o', 0xc3b1 => 'n', 
    			0xc3b2 => 'o', 0xc3b3 => 'o', 0xc3b4 => 'o', 0xc3b5 => 'o', 0xc3b6 => 'o', 0xc3b8 => 'o', 0xc3b9 => 'u', 0xc3ba => 'u', 
    			0xc3bb => 'u', 0xc3bc => 'u', 0xc3bd => 'y', 0xc3bf => 'y'
    		),
    		0xc4 => array(	
    			0xc480 => 'A', 0xc481 => 'a', 0xc482 => 'A', 0xc483 => 'a', 0xc484 => 'A', 0xc485 => 'a', 0xc486 => 'C', 0xc487 => 'c',
    			0xc488 => 'C', 0xc489 => 'c', 0xc48a => 'C', 0xc48b => 'c', 0xc48c => 'C', 0xc48d => 'c', 0xc48e => 'D', 0xc48f => 'd',
    			0xc490 => 'D', 0xc491 => 'd', 0xc492 => 'E', 0xc493 => 'e', 0xc494 => 'E', 0xc495 => 'e', 0xc496 => 'E', 0xc497 => 'e',
    			0xc498 => 'E', 0xc499 => 'e', 0xc49a => 'E', 0xc49b => 'e', 0xc49c => 'G', 0xc49d => 'g', 0xc49e => 'G', 0xc49f => 'g',
    			0xc4a0 => 'G', 0xc4a1 => 'g', 0xc4a2 => 'G', 0xc4a3 => 'g', 0xc4a4 => 'H', 0xc4a5 => 'h', 0xc4a6 => 'H', 0xc4a7 => 'h',
    			0xc4a8 => 'I', 0xc4a9 => 'i', 0xc4aa => 'I', 0xc4ab => 'i', 0xc4ac => 'I', 0xc4ad => 'i', 0xc4ae => 'I', 0xc4af => 'i',
    			0xc4b0 => 'I', 0xc4b1 => 'i', 0xc4b2 => 'IJ', 0xc4b3 => 'ij', 0xc4b4 => 'J', 0xc4b5 => 'j', 0xc4b6 => 'K', 0xc4b7 => 'k',
    			0xc4b8 => 'k', 0xc4b9 => 'L', 0xc4ba => 'l', 0xc4bb => 'L', 0xc4bc => 'l', 0xc4bd => 'L', 0xc4be => 'l', 0xc4bf => 'L'
    		),
    		0xc5 => array(	
    			0xc580 => 'l', 0xc581 => 'L', 0xc582 => 'l', 0xc583 => 'N', 0xc584 => 'n', 0xc585 => 'N', 0xc586 => 'n', 0xc587 => 'N',
    			0xc588 => 'n', 0xc589 => 'n', 0xc58a => 'N', 0xc58b => 'n', 0xc58c => 'O', 0xc58d => 'o', 0xc58e => 'O', 0xc58f => 'o',
    			0xc590 => 'O', 0xc591 => 'o', 0xc592 => 'OE', 0xc593 => 'oe', 0xc594 => 'R', 0xc595 => 'r', 0xc596 => 'R', 0xc597 => 'r',
    			0xc598 => 'R', 0xc599 => 'r', 0xc59a => 'S', 0xc59b => 's', 0xc59c => 'S', 0xc59d => 's', 0xc59e => 'S', 0xc59f => 's',
    			0xc5a0 => 'S', 0xc5a1 => 's', 0xc5a2 => 'T', 0xc5a3 => 't', 0xc5a4 => 'T', 0xc5a5 => 't', 0xc5a6 => 'T', 0xc5a7 => 't',
    			0xc5a8 => 'U', 0xc5a9 => 'u', 0xc5aa => 'U', 0xc5ab => 'u', 0xc5ac => 'U', 0xc5ad => 'u', 0xc5ae => 'U', 0xc5af => 'u',
    			0xc5b0 => 'U', 0xc5b1 => 'u', 0xc5b2 => 'U', 0xc5b3 => 'u', 0xc5b4 => 'W', 0xc5b5 => 'w', 0xc5b6 => 'Y', 0xc5b7 => 'y',
    			0xc5b8 => 'Y', 0xc5b9 => 'Z', 0xc5ba => 'z', 0xc5bb => 'Z', 0xc5bc => 'z', 0xc5bd => 'Z', 0xc5be => 'z', 0xc5bf => 's'
    		),
    		0xc6 => array(	
    			0xc680 => 'b', 0xc681 => 'B', 0xc682 => 'B', 0xc683 => 'b', 0xc684 => 'B', 0xc685 => 'b', 0xc686 => 'O', 0xc687 => 'C',
    			0xc688 => 'c', 0xc689 => 'D', 0xc68a => 'D', 0xc68b => 'd', 0xc68c => 'd', 0xc68d => 'd', 0xc68e => 'E', 0xc68f => 'E',
    			0xc690 => 'E', 0xc691 => 'F', 0xc692 => 'f', 0xc693 => 'G', 0xc694 => 'G', 0xc695 => 'hv', 0xc696 => 'I', 0xc697 => 'I',
    			0xc698 => 'K', 0xc699 => 'k', 0xc69a => 'l', 0xc69b => 'l', 0xc69c => 'M', 0xc69d => 'N', 0xc69e => 'n', 0xc69f => 'O',
    			0xc6a0 => 'O', 0xc6a1 => 'o', 0xc6a2 => 'OI', 0xc6a3 => 'oi', 0xc6a4 => 'P', 0xc6a5 => 'p', 0xc6a6 => 'R', 0xc6a7 => 'S',
    			0xc6a8 => 's', 0xc6a9 => 'S', 0xc6aa => 'S', 0xc6ab => 't', 0xc6ac => 'T', 0xc6ad => 't', 0xc6ae => 'T', 0xc6af => 'U',
    			0xc6b0 => 'u', 0xc6b1 => 'U', 0xc6b2 => 'V', 0xc6b3 => 'Y', 0xc6b4 => 'y', 0xc6b5 => 'Z', 0xc6b6 => 'z', 
    			0xc6bb => '2', 0xc6bc => '5', 0xc6bd => '5'
    		),
    		0xc7 => array(	
    			0xc784 => 'DZ', 0xc785 => 'Dz', 0xc786 => 'dz', 0xc787 => 'LJ', 
    			0xc788 => 'Lj', 0xc789 => 'lj', 0xc78a => 'NJ', 0xc78b => 'Nj', 0xc78c => 'nj', 0xc78d => 'A', 0xc78e => 'a', 0xc78f => 'I', 
    			0xc790 => 'i', 0xc791 => 'O', 0xc792 => 'o', 0xc793 => 'U', 0xc794 => 'u', 0xc795 => 'U', 0xc796 => 'u', 0xc797 => 'U', 
    			0xc798 => 'u', 0xc799 => 'U', 0xc79a => 'u', 0xc79b => 'U', 0xc79c => 'u', 0xc79d => 'e', 0xc79e => 'A', 0xc79f => 'a', 
    			0xc7a0 => 'A', 0xc7a1 => 'a', 0xc7a2 => 'AE', 0xc7a3 => 'ae', 0xc7a4 => 'G', 0xc7a5 => 'g', 0xc7a6 => 'G', 0xc7a7 => 'g', 
    			0xc7a8 => 'K', 0xc7a9 => 'k', 0xc7aa => 'O', 0xc7ab => 'o', 0xc7ac => 'O', 0xc7ad => 'o', 
    			0xc7b0 => 'j', 0xc7b1 => 'DZ', 0xc7b2 => 'Dz', 0xc7b3 => 'dz', 0xc7b4 => 'G', 0xc7b5 => 'g', 0xc7b6 => 'H', 
    			0xc7b8 => 'N', 0xc7b9 => 'n', 0xc7ba => 'A', 0xc7bb => 'a', 0xc7bc => 'AE', 0xc7bd => 'ae', 0xc7be => 'O', 0xc7bf => 'o'
    		),
    		0xc8 => array(	
    			0xc880 => 'A', 0xc881 => 'a', 0xc882 => 'A', 0xc883 => 'a', 0xc884 => 'E', 0xc885 => 'e', 0xc886 => 'E', 0xc887 => 'e',
    			0xc888 => 'I', 0xc889 => 'i', 0xc88a => 'I', 0xc88b => 'i', 0xc88c => 'O', 0xc88d => 'o', 0xc88e => 'O', 0xc88f => 'o',
    			0xc890 => 'R', 0xc891 => 'r', 0xc892 => 'R', 0xc893 => 'r', 0xc894 => 'U', 0xc895 => 'u', 0xc896 => 'U', 0xc897 => 'u',
    			0xc898 => 'S', 0xc899 => 's', 0xc89a => 'T', 0xc89b => 't', 0xc89e => 'H', 0xc89f => 'h',
    			0xc8a0 => 'N', 0xc8a1 => 'd', 0xc8a2 => 'OU', 0xc8a3 => 'ou', 0xc8a4 => 'Z', 0xc8a5 => 'z', 0xc8a6 => 'A', 0xc8a7 => 'a',
    			0xc8a8 => 'E', 0xc8a9 => 'e', 0xc8aa => 'O', 0xc8ab => 'o', 0xc8ac => 'O', 0xc8ad => 'o', 0xc8ae => 'O', 0xc8af => 'o',
    			0xc8b0 => 'O', 0xc8b1 => 'o', 0xc8b2 => 'Y', 0xc8b3 => 'y', 0xc8b4 => 'l', 0xc8b5 => 'n', 0xc8b6 => 't', 0xc8b7 => 'j', 
    			0xc8b8 => 'db', 0xc8b9 => 'qp', 0xc8ba => 'A', 0xc8bb => 'C', 0xc8bc => 'c', 0xc8bd => 'L', 0xc8be => 'T', 0xc8bf => 's'
    		),
    		0xc9 => array(	
    			0xc980 => 'z', 0xc983 => 'B', 0xc984 => 'U', 0xc985 => 'V', 0xc986 => 'E', 0xc987 => 'e',
    			0xc988 => 'J', 0xc989 => 'j', 0xc98a => 'Q', 0xc98b => 'q', 0xc98c => 'R', 0xc98d => 'R', 0xc98e => 'Y', 0xc98f => 'y',
    			0xc990 => 'a', 0xc991 => 'a', 0xc992 => 'a', 0xc993 => 'b', 0xc994 => 'o', 0xc995 => 'c', 0xc996 => 'd', 0xc997 => 'd',
    			0xc998 => 'e', 0xc999 => 'e', 0xc99a => 'e', 0xc99b => 'e', 0xc99e => 'e', 0xc99f => 'j',
    			0xc9a0 => 'g', 0xc9a1 => 'g', 0xc9a2 => 'G', 0xc9a3 => 'g', 0xc9a4 => 'g', 0xc9a5 => 'h', 0xc9a6 => 'h', 0xc9a7 => 'h',
    			0xc9a8 => 'i', 0xc9a9 => 'i', 0xc9aa => 'i', 0xc9ab => 'l', 0xc9ac => 'l', 0xc9ad => 'l', 0xc9ae => 'lz', 0xc9af => 'm',
    			0xc9b0 => 'm', 0xc9b1 => 'm', 0xc9b2 => 'n', 0xc9b3 => 'n', 0xc9b4 => 'N', 0xc9b5 => 'o', 0xc9b6 => 'OE', 0xc9b7 => 'o', 
    			0xc9b8 => 'p', 0xc9b9 => 'r', 0xc9ba => 'r', 0xc9bb => 'r', 0xc9bc => 'r', 0xc9bd => 'r', 0xc9be => 'r', 0xc9bf => 'r'
    		),
    		0xca => array(	
    			0xca80 => 'R', 0xca81 => 'R', 0xca82 => 's', 0xca84 => 'j', 0xca87 => 't',
    			0xca88 => 't', 0xca89 => 'u', 0xca8a => 'u', 0xca8b => 'v', 0xca8c => 'v', 0xca8d => 'w', 0xca8e => 'y', 0xca8f => 'y',
    			0xca90 => 'z', 0xca91 => 'z', 0xca97 => 'c',
    			0xca99 => 'B', 0xca9a => 'e', 0xca9b => 'G', 0xca9c => 'H', 0xca9d => 'j', 0xca9e => 'k', 0xca9f => 'L',
    			0xcaa0 => 'q', 0xcaa3 => 'dz', 0xcaa4 => 'dz', 0xcaa5 => 'dz', 0xcaa6 => 'ts', 0xcaa7 => 'tf',
    			0xcaa8 => 'tc', 0xcaa9 => 'fn', 0xcaaa => 'ls', 0xcaab => 'lz', 0xcaae => 'h', 0xcaaf => 'h',
    			0xcab0 => 'h', 0xcab1 => 'h', 0xcab2 => 'j', 0xcab3 => 'r', 0xcab4 => 'r', 0xcab5 => 'r', 0xcab6 => 'r', 0xcab7 => 'w', 
    			0xcab8 => 'y', 0xcab9 => '', 0xcaba => '', 0xcabb => '', 0xcabc => '', 0xcabd => '', 0xcabe => '', 0xcabf => ''
    		),
    		0xcb => array(	
    			0xcb80 => '', 0xcb81 => '', 0xcb82 => '', 0xcb83 => '', 0xcb84 => '', 0xcb85 => '', 0xcb86 => '', 0xcb87 => '',
    			0xcb88 => '', 0xcb89 => '', 0xcb8a => '', 0xcb8b => '', 0xcb8c => '', 0xcb8d => '', 0xcb8e => '', 0xcb8f => '',
    			0xcb90 => '', 0xcb91 => '', 0xcb92 => '', 0xcb93 => '', 0xcb94 => '', 0xcb95 => '', 0xcb96 => '', 0xcb97 => '',
    			0xcb98 => '', 0xcb99 => '', 0xcb9a => '', 0xcb9b => '', 0xcb9c => '', 0xcb9d => '', 0xcb9e => '', 0xcb9f => '',
    			0xcba0 => '', 0xcba1 => '', 0xcba2 => '', 0xcba3 => '', 0xcba4 => '', 0xcba5 => '', 0xcba6 => '', 0xcba7 => '',
    			0xcba8 => '', 0xcba9 => '', 0xcbaa => '', 0xcbab => '', 0xcbac => '', 0xcbad => '', 0xcbae => '', 0xcbaf => '',
    			0xcbb0 => '', 0xcbb1 => '', 0xcbb2 => '', 0xcbb3 => '', 0xcbb4 => '', 0xcbb5 => '', 0xcbb6 => '', 0xcbb7 => '',
    			0xcbb8 => '', 0xcbb9 => '', 0xcbba => '', 0xcbbb => '', 0xcbbc => '', 0xcbbd => '', 0xcbbe => '', 0xcbbf => ''
    		),
    		0xcc => array(	
    			0xcc80 => '', 0xcc81 => '', 0xcc82 => '', 0xcc83 => '', 0xcc84 => '', 0xcc85 => '', 0xcc86 => '', 0xcc87 => '',
    			0xcc88 => '', 0xcc89 => '', 0xcc8a => '', 0xcc8b => '', 0xcc8c => '', 0xcc8d => '', 0xcc8e => '', 0xcc8f => '',
    			0xcc90 => '', 0xcc91 => '', 0xcc92 => '', 0xcc93 => '', 0xcc94 => '', 0xcc95 => '', 0xcc96 => '', 0xcc97 => '',
    			0xcc98 => '', 0xcc99 => '', 0xcc9a => '', 0xcc9b => '', 0xcc9c => '', 0xcc9d => '', 0xcc9e => '', 0xcc9f => '',
    			0xcca0 => '', 0xcca1 => '', 0xcca2 => '', 0xcca3 => '', 0xcca4 => '', 0xcca5 => '', 0xcca6 => '', 0xcca7 => '',
    			0xcca8 => '', 0xcca9 => '', 0xccaa => '', 0xccab => '', 0xccac => '', 0xccad => '', 0xccae => '', 0xccaf => '',
    			0xccb0 => '', 0xccb1 => '', 0xccb2 => '', 0xccb3 => '', 0xccb4 => '', 0xccb5 => '', 0xccb6 => '', 0xccb7 => '',
    			0xccb8 => '', 0xccb9 => '', 0xccba => '', 0xccbb => '', 0xccbc => '', 0xccbd => '', 0xccbe => '', 0xccbf => ''
    		)
    	);
    	$i=0;
    	$strlen=strlen($string);
    	$str="";
    	while ($i<$strlen) {
    		$ord=ord($string[$i]);
    		if ($ord>=195 && $ord<=204) {
    			$hex=dechex($ord);
    			while ($i<$strlen-1) {
    				if (ord($string[$i+1])>=128 && ord($string[$i+1])<=192) {
    					$hex=$hex.dechex(ord($string[$i+1]));
    					$i++;
    				} else {
    					break;
    				}
    			}
    			foreach ($diacriticsEquivalent as $key => $arr) {
    				if (hexdec($hex)>>8==$key) {
    					foreach ($arr as $k => $v) {
    						if (hexdec($hex)==$k) {
    							$str.=$v;
    							break;
    						}
    					}
    					break;
    				}
    			}
    		} else {
    			$str.=$string[$i];
    		}
    		$i++;
    	}
    	return $str;
    }
    0x4F

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut
    Salut CosmoKnacki

    Un grand merci pour ta contribution fort enrichissante. Tes remarques sont très pertinentes.

    Je m’intéresse particulièrement à ta pattern sur la fonction preg_replace qui substituerait ma combinaison actuelle plus gourmande ;

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    	function lettres_multiples($stri) //Gère les lettres doublés de manière anormale [PBLM : ne gère pas les accents]
    		{ //Parttout!! -> intégré dans les différentes fonctions de casse
    		$stri = trim(($stri)," "); //On supprime les espases en début et fin de chaînes ..
                    $stri = preg_replace('<([rnmstplé])\\1{2,}(?!\\1)>i','$1',$stri); //pour les lettres doublées, si plus de deux on remplace par une...
    		$stri = preg_replace('<([^rnmstplé0-9])\\1+(?!\\1)>i','$1', $stri); //pour les autres, si plus de une on remplace par une...
    		return $stri;
    		}
    Par rapport à ta regex cette combinaison :
    Laissera à tord les tirets et apostrophes quotes en début et fin de chaîne.
    Mais elle supprimera aussi les lettres multiples (Juliennnnnn -> Julien), respectant les lettres doublées utilisé dans la langue fr (Emmmmmma -> Emma) (limite Arthurrrrrr -> Arthurr… )

    Je souhaiterai aussi faire une version de ta regex qui supprimerait tous les espaces de la chaîne (toujours dans le cas d’un champ prénom).

    Malheureusement, malgré de nombreuses heures passées à essayer de faire une traduction littérale de ta regex, je suis contraint de me rendre à l’évidence.. Cela m’est impossible. Pourrais-tu, stp, me venir en aide afin que je puisse l’intégrer à mon système et puisse avoir la main pour pouvoir la faire évoluer à ma convenance. Mais aussi évoluer dans ma compréhension des mécaniques de regex, bien complexe.

    Je ne comprends pas pourquoi le second argument de la fonction, $replacement, est laissé vide.
    Enfin ‘~’correspond à ‘#’ ?

    Voici mon ébauche :

    NB: Une backreference (\K) permet qu'une sous-expression précédemment mise en correspondance soit ensuite identifiée dans la même expression régulière.

    « Ce qui commence par au moins un tiret, apostrophe, quote, espace
    OU fini par au moins un tiret ou un espace
    OU au moins un espace suivi d'un tiret, apostrophe, quote … ??? »

    Je te remercie et reste impatiemment dans l’attente de te lire.

    Cdlmt.

  10. #10
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Concernant la correction automatique d'une entrée utilisateur, il ne faut pas perdre de vue que, d'une part l'utilisateur est responsable de ce qu'il écrit, et d'autre part qu'il est impossible d'envisager tous les cas de figures possibles.
    • Pour le premier point, la meilleur arme dont tu disposes est la page de confirmation.
    • Pour le deuxième, tu ne peux rien y faire. Par exemple avec les lettres doublées, tu risques de faire des "corrections" inappropriées avec des prénoms comme Isaac ou Emmett. Dans certaines langues comme le russe les consonnes triplées sont aussi possibles. Il suffit qu'un prénom russe soit transcrit de manière brute de l'alphabet cyrillique vers l'alphabet latin et tu te retrouves avec trois fois de suite la même consonne (Maintenant je ne suis pas expert en Russe). Autant on pourrait extraire certaines "règles" en ce qui concerne les noms communs en français, autant les noms propres peuvent être complètement imprévisibles.


    Le \K n'a rien à voir avec les backreferences, le \K sert juste à éliminer du résultat tous ce qui est à sa gauche. Par exemple echo preg_replace('~a\Kb~', '', 'bab'); affichera ba car le a se trouve à la gauche du \K. Le premier b n'est pas trouvé car il doit belle et bien y avoir un a avant pour qu'il y ait correspondance. Pour résumer, tous ce qui est à la gauche d'un \K est bien consommé par le moteur de regex mais est in fine exclu du résultat.
    Cette fonctionnalité permet d'éviter de créer des groupes de captures (pour obtenir le même résultat, il aurait fallu écrire: echo preg_replace('~(a)b~', '$1', 'bab');). Elle permet aussi de passer outre la limitation des test arrières (lookbehind) dans lequel une sous-pattern de longueur variable est interdite (on ne peut pas écrire ~(?<=ab*c)d~ par contre on peut faire ~ab*c\Kd~).

    Voici une version détaillée de la première pattern (J'ai placé les espaces entre crochets pour les rendre visible):
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ~        # délimiteur
    ^ [-’' ]+        # un ou plusieur espaces, tirets, quotes ou apostrophes en début de chaîne
    |              # OU
    [- ]+ $          # un ou plusieurs espaces ou tirets en fin de chaîne
    |              # OU
    [ ]+ (?=['’-])   # un ou plusieurs espaces suivi d'un quote, d'une apostrophe ou d'un tiret (1)
    |              # OU
    [ ] \K [ ]+      # un espace puis un ou plusieurs espaces
    |              # OU
    - \K (?:[ ]+|-+) # un tiret puis un ou plusieurs espaces ou un ou plusieurs tirets
    |              # OU
    ’ \K ’+          # une apostrophe puis une ou plusieurs apostrophes
    |              # OU
    ' \K '+          # un quote puis un ou plusieurs quotes
    ~        # délimiteur
    u    # modificateur pour gérer les chaînes UTF8
    S    # modificateur permettant une optimisation (2)
    (1) (?=...) est un "test avant" ou "lookahead" en anglais, il permet de vérifier que la position actuelle est bien suivie de la sous pattern qu'il contient (les caractères à droite de sa position) sans pour autant que celle ci fasse partie du résultat:echo preg_replace('~a(?=b)~', '', 'abaa'); affichera baa. Contrairement au \K les caractères ne sont pas consommés, si bien que echo preg_replace('~[ab](?=b)~', '', 'babc'); renverra bc.

    (2) Le modificateur S déclenche une optimisation du moteur de regex dans ce cas précis. C'est à dire quand la pattern débute ou est (comme ici) une alternative de plusieurs branches. En temps normal le moteur de regex teste toutes les alternatives une par une à chaque caractère de la chaîne en avançant de gauche à droite, donc plus il y a de branches et plus la chaîne est longue, plus il y a de tests potentiellement inutiles. Avec l'option S, la pattern est d'abord analysée plus finement pour déterminer par quels caractères les différentes branches de l'alternative peuvent commencer. Ceci fait, un algorithme rapide recherche les positions avec ces caractères dans la chaîne, ce qui fait que les branches ne seront testées qu'aux positions trouvées en excluant toutes les positions inintéressantes. (Je dois bien avouer que dans le cas présent c'est un peu de l'enculage de mouches, voire contre-productif, parce que la longueur des chaînes sera à tout casser de 20 caractères. Par contre c'est redoutable quand la chaîne est plus longue.)

    Le délimiteur de pattern est libre en PHP, tu peux utiliser tout ce que tu veux comme caractères spéciaux, y compris des choix douteux comme des caractères ayant une signification spécial dans une pattern (les parenthèses, les crochets, | $ ^ ...) ce qui est une très mauvaise idée. Comme tu as pu le voir tu peux aussi utiliser le couple < >. Moi j'utilise souvent le tilde pour éviter d'avoir à échapper dés qu'il faut mettre un slash dans la pattern, et j'évite aussi le # pour pouvoir placer des commentaires dans la pattern si ça me chante.

    À propos de l'échappement des antislashes (backslashes) dans les patterns: Il n'est utile que dans certains cas. Certains diront que puisque ça ne cause pas de problèmes autant les échapper systématiquement. Ma politique en la matière est différente, elle consiste à échapper uniquement quand c'est nécessaire, histoire de faire comprendre que l'on a compris au gens qui comprennent, et de faire se poser des questions au gens qui ne comprennent pas pour qu'un jour ils comprennent! C'est clair?
    Bref, il n'est pas utile d'écrire \\1 quand on se trouve dans une chaîne de caractère entre simple quotes car PHP n'interprète pas les séquences d'échappement (ou quoi que ce soit d'autre) dans les chaînes entre simple quotes (ou dans les chaînes nowdoc), \1 fait très bien l'affaire et sera transmise au moteur de regex qui lui l'interprétera comme une séquence d'échappement désignant une back-reference. Si \\1 lui est transmis, il devra ignorer l'antislash surnuméraire.
    Là où il est nécessaire de doubler l'antislash d'une back-reference c'est quand on est dans une chaîne entre double quotes (ou heredoc) pour éviter la confusion avec la notation octale d'un caractère: echo "\100"; affiche @. On doit alors doubler l'antislash pour figurer un antislash litéral: echo "\\100"; affiche bien \100.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  11. #11
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut
    Littéralement V2:
    On supprime (remplacé par rien):
    - ce qui commence par au moins un tiret, une apostrophe, une quote ou un espace (^[-’' ]+)
    - ce qui fini par un tiret ou un espace ([- ]+$)
    - l'espace, s'il est suivi d'un tiret, d'une apostrophe ou d'une une quote ( +(?=['’-]))

    - L'espace, s'il est suivi d'un espace?? (a quoi sert /K???) ( +(?=['’-])
    Puis après ça se complique vraiement trop...
    Que signifie K/?
    Que signifie l'assertion (?:motif) ? je ne l'a retrouve nulle part..

    Merci!!!

  12. #12
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut
    Excellent !!
    Merci CosmoKnacki !!!
    Je note tes deux premières remarques et fait évoluer mon système en conséquence.
    Merci pour ta patience, ta pédagogie et ta réactivité.
    Toutes tes explications m’ont permis de bien comprendre ta pattern de correction automatique, sa construction et toute son intérêt. De mieux appréhender les regex en général et la fonction preg_replace.

    Je comprends bien ta politique en matière d'échappement des antislashes (backslashes) dans les patterns, faut vraiment que les gens comprennent…

    Par contre bien qu’ayant compris son rôle dans la pattern, je ne définie toujours pas l’assertion (?:motif)..

  13. #13
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut
    Concernant la casse je ne la contrôle plus dans ma regex mais j’applique les fonctions suivantes :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $stri = mb_convert_case($stri, MB_CASE_LOWER, "UTF-8");
    $stri = mb_convert_case($stri, MB_CASE_TITLE, "UTF-8");
    Toujours dans le cas d’un champ prénom ces fonctions trouve leur limite puisqu’elles ne mettent pas de majuscule après une apostrophe ou une quote (seulement après un espace ou un tiret). Pire, si l’utilisateur a mis une majuscule après un apostrophe, la lettre sera mise en minuscule… (cas prénom D’Arcy, N’Jie..)
    Afin de palier ce défaut je souhaite mettre la lettre en majuscule après un apostrophe ou une quote j’ai essayé deux trucs en sans succès
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    $position = mb_strpos ($stri, "’|'"); 
    if ($position !== false) 
    	{
    	echo 'il y a apostrophe ou quote et traitement en positoin'.$position;
    	$stri = mb_strtoupper(mb_substr($stri, $position+1, $position+2,'utf-8'),'utf-8');
    	}
    	return $stri;
    Puis
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    $stri = preg_replace("~'|’\K(?=[{Latin}]){1}~", mb_strtoupper, $stri);
    Merci de votre aide !

  14. #14
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Pour faire un "mb_ucwords" (fonction qui n'existe malheureusement pas), tu peux utiliser preg_replace_callback:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    $str = preg_replace_callback('~\b(\p{Latin})(\p{Latin}*)~u',
        function ($m) { return mb_strtoupper($m[1], 'UTF8') . mb_strtolower($m[2], 'UTF8'); }, $str);
    Pour ce qui est de (?:...) tu peux consulter le tutoriel de Guillaume Rossolini sur le site ou le manuel PHP.
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  15. #15
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut
    Excellent parfait!!
    Quelle bonne idée j'ai pu avoir d'ouvrir cette discussion!

    Toujours dans ce même souci d'évolution et d'indépendance du code introduit dans mon système pourrais-tu, stp, me valider la traduction littérale que je fais de l’utilisation de la fonction preg_replace_callback avec cette pattern et fonction?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    \b -> limite de mot
    (\p{Latin}) : On apllique sur le premier mot latin la fonction $m (1ère lettre en majuscule le reste en minuscule)
    (\p{Latin}*) : S'il existe un ou plusieurs autre(s) mot(s) on applique la foncion $m
    Question de curiosité... je ne comprends pas pourquoi la fonction marche ainsi, ma compréhension ma logique m'aurait conduit à faire plutôt
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    function ($m) { return mb_strtoupper($m[0], 'UTF8') . mb_strtolower($m[1], 'UTF8'); }
    Je te remercie.

  16. #16
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    \b est bien la limite de mot (word boundary). Pour être plus précis, c'est en fait un peu plus subtile que ça. \b matche la position entre un caractère qui appartient à la classe de caractères \w et "autre chose". Cet "autre chose" pouvant être tout caractère n'appartenant pas à la classe de caractère \w ou le début de la chaîne ou la fin de la chaîne.

    Par défaut (sans le modificateur u), la classe \w est équivalente à la classe de caractères suivante: [a-zA-Z0-9_].
    Mais le modificateur u a un autre effet que d'offrir la capacité de lire les chaînes UTF8: Il étend les raccourcis de classes de caractères \w \d \s \h \v à l'unicode (à la base, ces classes ne contiennent que des caractères ASCII).

    Donc si on utilise le modificateur u, la classe \w va être étendue à toutes les lettres et à tous les chiffres de la table unicode, plus l'underscore, ce qui a donc pour effet de modifier également le comportement de \b. Exemples:
    • ~\bc~ matchera "àc" car "à" ne fait pas partie de \w
    • ~\bc~u ne matchera pas "àc" car "à" fait partie de \w


    NB: il est possible d'obtenir les deux effets du modificateur u séparément en plaçant (*UTF8) en début de pattern (ou (*UTF), (*UTF16), voire (*UTF32), tout dépend des directives de compilation du module pcre qui on été utilisées pour produire la configuration PHP) pour que la chaîne soit lue en UTF8, et en plaçant (*UCP) en début de pattern également pour étendre les raccourcis de classes de caractères à l'unicode. (à noter qu'utiliser l'un sans l'autre n'est pas souvent utile.)

    Attention à t'exprimer en termes précis (sans ambiguïté): \p{Latin} représente une lettre, pas un mot.

    En ce qui concerne $m[1] et $m[2], c'est simple, par convention $m[0] désigne l'ensemble de la correspondance, $m[1], le premier groupe de capture, $m[2] le second, etc.

    Autre chose, une (?:ho|e)rreur sur un précédent post: (?=truc){1} n'a aucun sens (et doit sûrement provoquer une erreur). (?=...) est juste un test, on le qualifie aussi de "zero width assertion" (littéralement: assertion de largeur nulle) donc le quantifier ou le répéter n'a pas de sens. D'autre part le quantificateur {1} n'a aucune raison d'être puisque par défaut chaque token dans une pattern est présent une fois (~a~ match "a", inutile d'écrire ~a{1}~ pour parvenir au même résultat).
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

  17. #17
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut
    Ouhaaa, excellent !

    Donc dans notre cas le « autre chose » (attendu) est le tiret, l’espace, l’apostrophe ou la quote…

    Je n’avais pas vraiment compris le \p…
    Pour la fonction avec $m[1], $m[2]… je pensais qu’elle ciblait des positions et non des groupes de capture. A la différence des positions, les groupes de capture commence donc bien par 1 et non 0, puisque le 0 « désigne l'ensemble de la correspondance ».

    De ce fait une meilleure traduction littérale serait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    \b -> limite de mot (interrompue dès que != de \w)
    	(\p{Latin}) : du premier mot, on capture la première lettre latine [1] et on capture le reste des lettre(s) latine(s) [2]
    	et on applique la fonction $m on met en majuscule le premier groupe de capture et en minuscule le second groupe.
    	(\p{Latin}*) : S'il existe un ou plusieurs autre(s) mot(s), on capture la première lettre latine [1] et on capture le reste des lettre(s) latine(s) [2], puis...
    	... On applique la fonction $m on met en majuscule le premier groupe de capture et en minuscule le second groupe.
    Concernant le modificateur « u , ça se complique…
    Je conclu bien qu’il est alors quasi obligatoire à l’unicode…
    Mais je ne comprends pas la phrase « Il étend les raccourcis de classes de caractères \w \d \s \h \v à l'unicode » (…et donc l’exemple)
    Ces classes ne contiennent que des caractères ASCII, mais le modificateur ne va pas ajouter de nouveaux caractères qui seraient sur plusieurs octets.. tel que les accents… Quel intérêt de la présence du modificateur ‘u’ avec \w… je comprends avec la classe {Latin} qui contient des caractères sur plusieurs octets…
    Enfin, je vais investir davantage sur ce sujet, comprendre l’exemple, me poser les bonnes questions, pour éventuellement te poser les bonnes !! ;-)

    Un grand MERCI

  18. #18
    Nouveau membre du Club
    Homme Profil pro
    Consultant informatique
    Inscrit en
    Janvier 2015
    Messages
    29
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Consultant informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Janvier 2015
    Messages : 29
    Points : 26
    Points
    26
    Par défaut
    Pour revenir à la regex et afin de clore la discussion ;

    1/ J’ai essayé, fort de tes remarques de modifier ma regex, dans l’espoir de tendre vers la tienne, j’aboutie sur cette dernière
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    $regex_1 = "#^[A-ZÀÂÄÆÇÉÈÊËÎÏÔŒÙÛÜŸ]{1}([a-zàáâäæçéèêëîïôœùûüÿ]+|([a-zàáâäæçéèêëîïôœùûüÿ]*(-|'|’)[a-zA-ZàáâäæçéèêëîïôœùûüÿÀÂÄÆÇÉÈÊËÎÏÔŒÙÛÜŸ]+))
    $regex_1 = "~^\p{Latin}{1}(\p{Latin}+|(\p{Latin}*(-|'|’)\p{Latin}+))*[']?$~u";
    Quelle véritable différence avec la tienne ? Ne peut-on pas se passer des (?:motif) ? (quel est l’impact de leur absence ? plus gourmande puisque capture inutile ?) Pourquoi dissocies-tu les tirets et espaces des apostrophes et quote ([- ]|['’] => [- '’]) ?
    (aie !!!! le {1} -> à remplacer par ’+’)

    2/ Si je pars de ta regex.
    Toujours dans ce même souci d’indépendance, je cherche à faire sa traduction littérale, est-ce bon ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    "~^\p{Latin}+(?:(?:[- ]|['’] ?)\p{Latin}+)*['’]?$~u"
    	^\p{Latin}+		Commence par une ou plusieurs lettre(s) latine(s) 
    	(...) *			Puis par aucun, un ou plusieurs fois le groupe :
    	(?:				Peut-être suivi (capturé) par...
    	(?:[- ]|['’] ?)				Peut-être suivi (capturé) par un tiret ou un espace
    	\p{Latin}+)				... (puis ) une ou plusieurs lettre(s) latine(s)
    	[']?			Puis par aucun ou un apostrophe ou une quote
    Je ne comprends pas le « ? » positionné avant une parenthèse fermante ?

    Merci Beaucoup.

  19. #19
    Invité
    Invité(e)
    Par défaut
    Personnellement, ce que je retiens* avant tout, c'est :

    Citation Envoyé par CosmoKnacki Voir le message
    Concernant la correction automatique d'une entrée utilisateur, il ne faut pas perdre de vue que,
    • d'une part l'utilisateur est responsable de ce qu'il écrit,
    • et d'autre part qu'il est impossible d'envisager tous les cas de figures possibles.
    Quelle que soit la regex que tu écriras, elle rencontrera tôt ou tard un prénom qui "ne rentre pas dans les clous".





    *Cela dit, je salue bien bas l'expertise de CosmoKnacki

  20. #20
    Expert éminent Avatar de CosmoKnacki
    Homme Profil pro
    Justicier interdimensionnel
    Inscrit en
    Mars 2009
    Messages
    2 858
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Charente Maritime (Poitou Charente)

    Informations professionnelles :
    Activité : Justicier interdimensionnel

    Informations forums :
    Inscription : Mars 2009
    Messages : 2 858
    Points : 6 556
    Points
    6 556
    Par défaut
    Merci Jreaux.

    @kint:

    Ne peut-on pas se passer des (?:motif) ? (quel est l’impact de leur absence ? plus gourmande puisque capture inutile ?)
    Pour ce qui est du détail de ta pattern, attention à ne pas confondre: (?:...) est un groupe non capturant, et (...) est un groupe capturant.

    Détail de la seconde pattern:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    ~                      # délimiteur
    ^                      # ancre de début de chaîne
    \p{Latin}+             # une ou plusieurs lettres latines (accentués ou pas, mais aussi les trucs comme: ç œ æ ...)
    (?:                    # groupe non capturant pour les éventuels autres mots
     
        (?:[- ]|['’] ?)    # séparer par soit un tiret, un espace, un quote avec un éventuel espace, une apostrophe avec un éventuel espace
                           # (le choix de ne pas tout mettre dans le même sac [-']+ découle d'une part des remplacements effectués avec la
                           # pattern précédente et d'autre part de la volonté de garantir une certaine logique syntaxique: on n'est pas censé
                           # se retrouver avec "Jean -Paul" ou "Jean- Paul", par contre "O'Ryan" ou un prénom composé dont le premier comporte une
                           # apostrophe finale "Vinc’ Daniel" sont autorisés)
     
        \p{Latin}+         # mot de une ou plusieurs lettres
    )*                     # on répète le tout 0, 1 ou plusieurs fois
    ['’]?                  # éventuel apostrophe ou quote final
    $                      # ancre de fin de chaîne
    ~                      # délimiteur
    u                      # modificateur u
    Le ? avant la parenthèse fermante rend l'espace optionnel.




    Ces classes ne contiennent que des caractères ASCII, mais le modificateur u ne va pas ajouter de nouveaux caractères qui seraient sur plusieurs octets.. tel que les accents
    Si justement, c'est exactement ce qu'il fait avec la classe \w. \w va alors contenir les lettres et chiffres ASCII et l'underscore, mais aussi n'importe quelles lettres accentuées ou pas de n'importe quel alphabet (idem pour les chiffres). \p{Latin} se retrouve donc être un sous groupe de \w (sans l'underscore, les chiffres et les alphabets non latin), c'est pour cette raison que l'on peut utiliser \b devant ou à la fin d'un mot dans ce contexte.

    Concernant la pattern ~^\p{Latin}{1}(\p{Latin}+|(\p{Latin}*(-|'|’)\p{Latin}+))*[']?$~u:
    • Elle est fonctionnelle et produit pratiquement le même résultat que la mienne à l'exception qu'elle n'autorise pas l'espace entre deux mots ("Jean Paul") et un éventuel espace après un quote ou une apostrophe ("Vinc’ Daniel", mais libre à toi de faire ce choix).
    • aaargghh!! \p{Latin}{1} => \p{Latin}, le quantificateur {1} ne sert à rien (en toute circonstance).
    • Le groupe qui encadre \p{Latin}*(-|'|’)\p{Latin} n'est pas utile, tu peux l'enlever.
    • Les groupes n'ont pas besoin d'être capturant donc: (...) => (?:...).
    • Si tu n'autorises pas l'espace après un quote ou une apostrophe, tu peux remplacer l'alternative (-|'|’) par une classe de caractères [-'’ ] (en ajoutant l'espace donc)
    • Ta pattern n'autorise pas non plus que le premier mot, quand il y en a plusieurs, n'ait qu'une seule lettre ^\p{Latin}{1}(\p{Latin}+|... (il en faut minimum 2, donc au revoir "O'Ryan").


    À se stade, on aboutit à ~^\p{Latin}(?:\p{Latin}+|\p{Latin}*[-'’ ]\p{Latin}+)*[']?$~u. On a juste enlevé ce qui était inutile et ajouté l'espace comme séparateur de mots.

    Il reste à solutionner le problème du premier mot qui ne peut pas comporter un seul caractère. Mais avant cela, on va factoriser l'expression.

    Les deux branches de ton alternative commencent par \p{Latin}+ et \p{Latin}*. La première branche peut aussi s'écrire \p{Latin}*\p{Latin}, donc on peut mettre \p{Latin}* en facteur et le sortir de groupe, ce qui donne:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ~^\p{Latin}+(?:\p{Latin}|[-'’ ]\p{Latin}+)*[']?$~u
    Et là on se rend clairement compte que cette première branche ne sert à rien si ce n'est à empêcher le premier mot d'avoir un seul caractère quand il y en a plusieurs, donc on la supprime et on obtient:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ~^\p{Latin}+(?:[-'’ ]\p{Latin}+)*[']?$~u
    Brachygobius xanthozonus
    Ctenobrycon Gymnocorymbus

Discussions similaires

  1. [MySQL] Problème de simple quote dans le champ de recherche
    Par mesken dans le forum PHP & Base de données
    Réponses: 10
    Dernier message: 29/03/2012, 10h05
  2. Sudo problème avec les simples quotes
    Par Tronche dans le forum Shell et commandes GNU
    Réponses: 5
    Dernier message: 23/03/2007, 12h02

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo