#1 Sun 10 September 2023 14:21
- Pascal1968
- Participant occasionnel
- Date d'inscription: 21 Aug 2023
- Messages: 10
QGIS: Extraction partielle chaine de caracteres
Bonjour à toutes et tous,
J'ai un petit souci d'extraction partielle d'une chaîne de caractères d'un champ pour remplir un autre champ.
Je sais qu'il y déjà quantité de sujet du même style, mais l'expression que j'utilise fonctionne parfaitement sauf pour un cas en particulier.
Si quelqu'un sait me dépanner ... ?
Soit une couche avec un champ "Fullname" comprenant des valeurs de type :
Abies concolor => Genus + Species
Acer campestre _'Elsrijk' => Genus + Species + Cultivar
Carpinus betulus _'Albert Beeckman' => Genus + Species + Cultivar (cultivar en deux mots)
Ilex _'Nellie R. Stevens' => Genus + Cultivar
Populus (x) canadensis => Genus + Species (mais avec "(+)" devant le nom d'espèce)
Salix (x) sepulcralis _'Chrysocoma' => Genus + Species (mais avec "(+)" devant le nom d'espèce) + Cultivar
Je souhaite remplir automatiquement un champ "Genus", un champ "Species" et un champ "Cultivar" sur base de "Fullname".
"Genus" est le premier mot de "Fullname".
"Species" est le second mot sans quotes de "Fullname" lorsque ce deuxième mot existe.
"Cultivar est le second ou troisième mot de "Fullname" et est toujours entre deux quotes.
Pour "Genus", en valeur par défaut, je mets :
Code:
array_get (string_to_array ("Fullname",' '), 0)
Pour "Cultivar", en valeur par défaut, je mets :
Code:
array_get (string_to_array ("Fullname",'_'), 1)
Les deux expressions fonctionnent à marveille.
Le problème est pour le champ "Species".
En valeur par défaut, pour résoudre tous les différents cas, je mets:
Code:
CASE WHEN length("Fullname")-length(replace("Fullname", '(x)', '')) = 3 THEN 'x '||array_get (string_to_array ("Fullname",'(x)'), 1) ELSE array_get (string_to_array ("Fullname",' '), 1) END
Cela fonctionne dans tous les cas sauf un: les valeur du type Salix (x) sepulcralis _'Chrysocoma' qui renvoient "x sepulcralis _'Chrysocoma'".
Il y a donc la partie ( _'Chrysocoma') en trop.
Voir capture d'écran : [img]https://imagizer.imageshack.com/img923/2386/5YvlLf.jpg[/img]
J'ai essayé de comprendre l'expression regexp_substr, mais sans succès
Elle me semble pourtant être adaptée à ce que je souhaite faire : extraire une partie d'une chaîne de caractères, toujours comprise entre les deux mêmes caractères.
Début = la parenthèse fermée.
Fin = le underscroll (en réalité, l'espace avant le underscroll).
Une âme charitable pourrait-elle me mettre sur la bonne piste ?
D'avance merci !
Dernière modification par SANTANNA (Sun 10 September 2023 19:57)
Hors ligne
#2 Sun 10 September 2023 23:09
- p.jeremie
- Participant assidu
- Lieu: Valence
- Date d'inscription: 10 Sep 2017
- Messages: 427
Re: QGIS: Extraction partielle chaine de caracteres
J'ai essayé quelque chose qui pourrait t'aller, avec regexp_matches.
Code:
regexp_matches( replace(fullname,'(x) ',''),'^([a-zA-Z0-9_]+) ([a-zA-Z0-9_]*) ?(_.+)*$')
Permet de récupérer une liste de toutes les chaînes repérées par l'expression rationnelle.
J'ai remplacé le (x) et l'espace qui le suit par une chaine vide pour ne pas à avoir à le gérer dans l'expression rationnelle. J'espère que j'ai bien compris et que tu ne souhaitais pas le récupérer dans tes champs ?
L'expression rationnelle récupère 3 groupes (ce sont les parenthèses qui servent à faire les groupes) qu'on récupère dans une liste :
- genus = le premier groupe de lettres ou chiffres [a-zA-Z0-9_]+ le ^ servant à indiquer que c'est le début de la ligne et le + pour indiquer 1 à n répétitions de lettres ou chiffres
- species = le deuxième groupe de lettres ou chiffres (mais peut aussi être vide, c'est à ça que sert le * : 0 à n répétitions de lettres ou chiffres)
- cultivar = après une deuxième espace optionnelle (?) on a à la suite un underscore suivi de n'importe quel caractère (.) répété entre 1 et n fois (+). Cet ensemble peut être présent 0 à n fois (*) et enfin fin de ligne ($)
Ensuite, pour récupérer le bon groupe, tu peux utiliser le array_get() :
Pour genus
Code:
array_get(regexp_matches( replace(fullname,'(x) ',''),'^([a-zA-Z0-9_]+) ([a-zA-Z0-9_]*) ?(_.+)*$'),0)
Pour species
Code:
array_get(regexp_matches( replace(fullname,'(x) ',''),'^([a-zA-Z0-9_]+) ([a-zA-Z0-9_]*) ?(_.+)*$'),1)
Pour cultivar
Code:
regexp_replace(array_get(regexp_matches( replace(fullname,'(x) ',''),'^([a-zA-Z0-9_]+) ([a-zA-Z0-9_]*) ?(_.+)*$'),2),'[_'']','')
J'ai ajouté un regexp_replace qui remplace les underscore et les quotes par une chaîne vide.
En espérant que ça réponde à ta problématique.
P.S. : si tu veux mieux comprendre les expressions rationnelles, un bon site est https://regex101.com/
Par exemple avec l'expression que je t'ai donnée et tes valeurs (sans le (x) que je supprime avant d'appliquer l'expression dans QGIS) : https://regex101.com/r/kqyWrZ/1
Dernière modification par p.jeremie (Sun 10 September 2023 23:13)
Hors ligne
#3 Mon 11 September 2023 14:58
- Pascal1968
- Participant occasionnel
- Date d'inscription: 21 Aug 2023
- Messages: 10
Re: QGIS: Extraction partielle chaine de caracteres
Salut Jérémie !
Grand merci pour cette réponse aussi rapide que complète !
Normalement, au niveau nomenclature des arbres, un cas comme Salix (x) sepulcralis _'Chrysocoma' s'écrit Salix x sepulcralis 'Chrysocoma'.
Seulement, au niveau des expressions que j'avais montées, il me fallait pouvoir distinguer ce qui est le nom du genre, le nom de l'espèce et le nom de la variété. Sans compter toutes les variantes qui ne comprenne pas de nom d'espèces ou qui possède un 'x' de liaison car ce sont des cultivars.
Bref, le "(x)" et le " _" me permettait sans trop d'effort au résultat.
Pour rire, le fait des parenthèses autour du "x" me permettait d'éviter que ma fonction ne s'arrête sur le "x" de "saliX" au lieu de s'arrêter sur le "x" de liaison :-) Ca m'a rendu ce truc-là.
Le redoublement de l'espacement n'était pas non plus une erreur. Il me permettait de ne pas avoir le nom du cultivar qui venait s'afficher avec celui de l'espèce. Mais, bon, je l'admets, c'est du bricolage.
De mon très rapide petit test au boulot, tes trois expressions fonctionnent presque à la perfection. Je constate simplement que je me suis mal exprimé sur quelques détails.
Pour le "(x)", tu as raison. Je souhaite effectivement pouvoir récupérer le "x" (sans les parenthèses) dans le champs "Species".
Pour le Salix (x) sepulcralis _'Chrysocoma', le résultat escompté est donc:
Genus : Salix
Species: x sepulcralis
Cultivar: 'Chrysocoma'
De même les guillemets simples (') qui entourent le nom du cultivar doivent aussi être conservés. Ce qui n'est pas le cas ici.
Penses-tu qu'il soit possible de modifier tes trois expressions pour les utiliser directement sur les noms réels sans mes "(x)" et " _" qui me servent à séparer genre/espèce/variété ?
Je vais m'attaquer ce soir au site que tu m'as conseillé et qui me semble effectivement très intéressant. On est jamais trop vieux pour apprendre.
Merci d'avance pour la suite !
Hors ligne
#4 Mon 11 September 2023 15:08
- p.jeremie
- Participant assidu
- Lieu: Valence
- Date d'inscription: 10 Sep 2017
- Messages: 427
Re: QGIS: Extraction partielle chaine de caracteres
De mon très rapide petit test au boulot, tes trois expressions fonctionnent presque à la perfection. Je constate simplement que je me suis mal exprimé sur quelques détails.
Pour le "(x)", tu as raison. Je souhaite effectivement pouvoir récupérer le "x" (sans les parenthèses) dans le champs "Species".
Pour le Salix (x) sepulcralis _'Chrysocoma', le résultat escompté est donc:
Genus : Salix
Species: x sepulcralis
Cultivar: 'Chrysocoma'
De même les guillemets simples (') qui entourent le nom du cultivar doivent aussi être conservés. Ce qui n'est pas le cas ici.
Penses-tu qu'il soit possible de modifier tes trois expressions pour les utiliser directement sur les noms réels sans mes "(x)" et " _" qui me servent à séparer genre/espèce/variété ?
Est-ce que tu peux fournir des exemples des noms réels afin de pouvoir se baser dessus ?
Hors ligne
#5 Mon 11 September 2023 15:18
- Pascal1968
- Participant occasionnel
- Date d'inscription: 21 Aug 2023
- Messages: 10
Re: QGIS: Extraction partielle chaine de caracteres
Re salut,
J'ai trouvé pour les guillemets simplets à réafficher. J'ai changé '[_'']' en '[_]' à la fin de l'expression.
Par contre, réafficher le "x" sans les parenthèses reste un problème pour moi.
En remplaçant ( replace(fullname,'(x) ','') par ( replace(fullname,'(x) ','x'), j'obtiens Species : xsepulcralis
Et si je remplace par ( replace(fullname,'(x) ','x '), j'obtiens Species: NULL
Je continue à chercher de mon côté.
Hors ligne
#6 Mon 11 September 2023 15:30
- Pascal1968
- Participant occasionnel
- Date d'inscription: 21 Aug 2023
- Messages: 10
Re: QGIS: Extraction partielle chaine de caracteres
Voici tous les cas "types" que j'ai pu rencontrer jusqu'à présent:
Abies alba => Genus : Abies et Species : alba
Acer campestre 'Elsrijk' => Genus : Acer Species : campestre et Cultivar : 'Elsrijk'
Acer platanoides 'Autumn Blaze' => Genus : Acer Species : platanoides et Cultivar : 'Autumn Blaze' (c'est une variation du cas précédent avec deux mots pour la variété (cultivar)
Aesculus x carnea => Genus : Aesculus et Species : x carnea
Salix x sepulcralis 'Chrysocoma'=> Genus : Salix Species : x sepulcralis et Cultivar : 'Chrysocoma'
Betula utilis var. jacquemontii => Genus : Betula Species : utilis et Cultivar : var. jacquemontii
Crataegus crus-galli => Genus : Crataegus et Species : crus-galli
Crataegus laevigata 'Paul's Scarlet' => Genus : Crataegus Species : laevigata et Cultivar : 'Paul's Scarlet'
Ilex 'Nellie R. Stevens' => Genus : Ilex Pas de Species et Cultivar : 'Nellie R. Stevens'
Je pense que tout y est :-)
Je ne peux pas dire que les botanistes nous ont faciliter la tâche pour faire des bases de données...
Merci d'avance !
Hors ligne
#7 Tue 12 September 2023 14:04
- Pascal1968
- Participant occasionnel
- Date d'inscription: 21 Aug 2023
- Messages: 10
Re: QGIS: Extraction partielle chaine de caracteres
Bonjour Jeremie,
Merci pour le site Regex101. Très intéressant. J'ai aussi fait le tour de deux trois sites explicatifs à ce sujet.
En partant de ton exemple, j'en suis arrivé ici pour le moment: https://regex101.com/r/tcwFZO/7
Pas parfait même si cela prend forme. je ne peux pas dire que je sois très doué de ce côté-là...
En annexe la capture d'écran avec mes commentaires. cela peut aider.
Merci d'avance !
Hors ligne
#8 Tue 12 September 2023 21:55
- p.jeremie
- Participant assidu
- Lieu: Valence
- Date d'inscription: 10 Sep 2017
- Messages: 427
Re: QGIS: Extraction partielle chaine de caracteres
Bonjour,
J'ai fait une version 8 puis finalement 9 de ta regex.
https://regex101.com/r/tcwFZO/9
Elle répond a priori à tous les cas que tu as mentionnés.
Code:
^([a-zA-Z]+) (x? ?[a-zA-Z-]*) ?(.*)$
3 groupes :
- une suite d'au moins 1 lettre (le '+')
(une espace)
- un groupe pouvant être vide car composé de : caractère x puis espace répétés chacun 0 ou 1 fois (le '?') puis des lettres ou un tiret répétés 0 à n fois (le '*')
(une espace optionnelle grâce au '?')
- un groupe composé de n'importe quel caractère (le '.') répété 0 à n fois (le '*')
et la fin de ligne (le '$')
Hors ligne
#9 Wed 13 September 2023 08:16
- Pascal1968
- Participant occasionnel
- Date d'inscription: 21 Aug 2023
- Messages: 10
Re: QGIS: Extraction partielle chaine de caracteres
Bonjour Jeremie,
C'est absolument parfait !
J'avais essayé de regrouper les deux parties composant le Species mais je m'y étais mal pris. J'avais fait deux sous-groupes dans le groupe de Species. Mais, apparemment je l'avais mal écrit. Manque de pratique
Encore merci pour ton aide et belle journée !
Pascal
Hors ligne