Aller au contenu

[Résolu] Petit lisp pour "sortir" un chiffre d'une chaine.


DenisHen

Messages recommandés

Bonjour à la communauté.

Voilà, je dois trouver le chiffre unique contenu dans une chaine, par exemple, dans "Ma80cm", j'aimerais isolé 80.

Si quelqu'un a une astuce, un bout de code, une idée... Je suis preneur...

Bien à toi la communauté.

Denis...

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Donc, tant que le premier caractère de la chaine en entrée n'est pas un chiffre, on supprime le premier caractère de la chaine en entrée.
Puis, tant que le premier caractère de la chaîne de la chaine en entrée est un chiffre, on ajoute ce caractère à la fin de la chaîne en sortie et on supprime le premier caractère de la chaine en entrée.

Voir les fonctions : while, substr, wcmatch, et strcat.

Ou, plus efficient, traiter les chaînes comme des listes de caractère ascii (nombres entiers en LISP). Voir les fonctions vl-string->list, vl-list->string et les fondamentales car, cdr et cons.

Ou encore, si la chaîne ne contient qu'un nombre, plus concis et élégant avec : vl-string->list, vl-list->string, vl-remove-if-not et lambda.

 

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

Test chaque caractère de la chaîne un par un, et si il y a un chiffre le met dans la variable strnb.

(Setq chaîne "Ma80cm")
(Setq I 0)
(Setq strnb nil)
(while (< (length chaîne) I)
(if (= (wcmatch (itoa (substr chaîne I 1)) "[0-9]") T)
(Setq strnb (strcat strnb (substr chaîne I 1)))
)
(Setq I (+ I 1))
)
(Princ strnb)

[Edit] je viens de voir qu'il manquait une parenthèse à la fin de "(setq strnb (strcat ...", erreur résolue.

Lien vers le commentaire
Partager sur d’autres sites

Comme l'a suggéré (gile) avec les fonctions (vl-***

Seul bémol si le caractère "." ou "-" se trouve n'importe où dans la chaîne, cela peut donner un résultat erroné!

(defun extract_num4str (str / )
	(atof (vl-list->string (vl-remove-if '(lambda (x) (or (< x 45) (> x 57))) (vl-string->list str))))
)

 

Choisissez un travail que vous aimez et vous n'aurez pas à travailler un seul jour de votre vie. - Confucius

Lien vers le commentaire
Partager sur d’autres sites

Bonjour à la communauté et merci à vous pour votre aide.

@(gile): j'ai bien saisis ton idée, mais je ne sais pas si j'y serais arrivé seul, j'ai encore un peu de mal avec wcmatch et je ne maitrise pas les vl-* et encore moins lambda.

@JPhil : ton code m'a permis de mieux appréhender les autres messages.

@bonuscad : ton code me convient parfaitement.

Encore merci à vous et à la communauté.

Denis...

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Il y a 10 heures, (gile) a dit :

tant que le premier caractère de la chaine en entrée n'est pas un chiffre, on supprime le premier caractère de la chaine en entrée.
Puis, tant que le premier caractère de la chaîne de la chaine en entrée est un chiffre, on ajoute ce caractère à la fin de la chaîne en sortie et on supprime le premier caractère de la chaine en entrée.

(defun fun1 (input / output)
  (while (not (wcmatch (substr input 1 1) "#"))
    (setq input (substr input 2))
  )
  (setq output "")
  (while (wcmatch (substr input 1 1) "#")
    (setq output (strcat output (substr input 1 1))
	  input (substr input 2)
    )
  )
  output
)

 

Il y a 10 heures, (gile) a dit :

Ou, plus efficient, traiter les chaînes comme des listes de caractère ascii (nombres entiers en LISP)

(defun fun2 (str / lst res)
  (setq lst (vl-string->list str))
  (while (and lst (not (< 47 (car lst) 58)))
    (setq lst (cdr lst))
  )
  (while (and lst (< 47 (car lst) 58))
    (setq res (cons (car lst) res)
	  lst (cdr lst)
    )
  )
  (vl-list->string (reverse res))
)

 

Il y a 10 heures, (gile) a dit :

Ou encore, si la chaîne ne contient qu'un nombre, plus concis et élégant

(defun fun3 (str)
  (vl-list->string
    (vl-remove-if-not
      '(lambda (c) (< 47 c 58))
      (vl-string->list str)
    )
  )
)

 

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

@JPhil, j'avais à peu près la même approche que toi, mais je ne m'en serais jamais sorti avec (wcmatch (itoa (substr chaîne I 1)) "[0-9]").

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Tous les chemins mènent à Rome ;)


Aurais-tu une idée afin d'extraire uniquement les caractères minuscules de la chaîne "Ma80cm" ?
Et quitte à faire l'exercice jusqu'au bout, extraire uniquement les caractères majuscules.
On peut aussi rajouter en bonus le grand défis des caractères accentués.

Lien vers le commentaire
Partager sur d’autres sites

Peut-être avec (wcmatch (itoa (substr chaîne I 1)) "[a-z]") ?

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Suite à ma consultation du magnifique "Introduction a AutoLISP" de notre ami (gile) et au site  "da-code" de notre ami didier, peut-être ceci :
(wcmatch (substr chaîne I 1) "[a-z,éèçàâäêëûüîï]") (je viens juste de remarquer que toutes les voyelles étaient sur la première ligne du clavier...).
Attention, je n'ai rien testé, c'est juste une idée...

 

Windows 11 / AutoCAD 2024

Sur terre, il y a 10 types de personnes, celles qui comptent en binaire et les autres (developpez.net).
Davantage d'avantages, avantagent davantage (Bobby Lapointe).
La connaissance s'accroît quand on la partage (Socrate).
Tant va la cruche à l'eau que l'habit n'amasse pas mousse avant de l'avoir tué. (Moi)

Lien vers le commentaire
Partager sur d’autres sites

Coucou,

J'avais déjà une fonction en stock pour chat 🙂

;                                       []-----------------------[] Wildcard-trim []-----------------------[]                                       ;
;--- Date of creation       > 10/12/2021                                                                                                            ;
;--- Last modification date > 10/12/2021                                                                                                            ;
;--- Author                 > Luna                                                                                                                  ;
;--- Version                > 1.0.0                                                                                                                 ;
;--- Class                  > "BaStr"                                                                                                               ;

;--- Goal and utility of the main function                                                                                                          ;
;   When used for functions (vl-string-*-trim), lists all the characters corresponding to the specified pattern in the form of a list from the 256  ;
;   characters present in the ASCII table.                                                                                                          ;
;                                                                                                                                                   ;
;--- Declaration of the arguments                                                                                                                   ;
; The function (Wildcard-trim) have 1 argument(s) :                                                                                                 ;
;   --•  w                      > correspond to the pattern that each character needs to match                                                      ;
;     (type w) = 'STR                           | Ex. : "#", "@", "~#", ".,#", ...                                                                  ;
;                                                                                                                                                   ;
;--- Return                                                                                                                                         ;
;   The function (Wildcard-trim) returns a list of characters (1 single character per string) whose characteristics correspond to the wildcard      ;
;   specified in argument (see wcmatch for the Wild-Card Characters).                                                                               ;
;     Ex. : (Wildcard-trim "#") returns ("0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "²" "³" "¹")                                                       ;
;           (Wildcard-trim "@") returns ("A" "B" "C" "D" "E" "F" "G" "H" "I" "J" "K" "L" "M" "N" "O" "P" "Q" "R" "S" "T" "U" "V" "W" "X" "Y" "Z"    ;
;                                        "a" "b" "c" "d" "e" "f" "g" "h" "i" "j" "k" "l" "m" "n" "o" "p" "q" "r" "s" "t" "u" "v" "w" "x" "y" "z"    ;
;                                        "ƒ" "Š" "Œ" "Ž" "š" "œ" "ž" "Ÿ" "ª" "µ" "º" "À" "Á" "Â" "Ã" "Ä" "Å" "Æ" "Ç" "È" "É" "Ê" "Ë" "Ì" "Í" "Î"    ;
;                                        "Ï" "Ð" "Ñ" "Ò" "Ó" "Ô" "Õ" "Ö" "Ø" "Ù" "Ú" "Û" "Ü" "Ý" "Þ" "ß" "à" "á" "â" "ã" "ä" "å" "æ" "ç" "è" "é"    ;
;                                        "ê" "ë" "ì" "í" "î" "ï" "ð" "ñ" "ò" "ó" "ô" "õ" "ö" "ø" "ù" "ú" "û" "ü" "ý" "þ" "ÿ")                       ;
;                                                                                                                                                   ;
;--- Historic list of the version with their modification status                                                                                    ;
; +------------+----------------------------------------------------------------------------------------------------------------------------------+ ;
; |   v1.0.0   |   Creation of the function                                                                                                       | ;
; +------------+----------------------------------------------------------------------------------------------------------------------------------+ ;
;                                                                                                                                                   ;

(defun wildcard-trim (w / i lst a)

  (repeat (setq i 256)
    (if (wcmatch (setq a (chr (setq i (1- i)))) w)
      (setq lst (cons a lst))
    )
  )
  lst

)

Du coup pour répondre au challenge, je donnerai cette version :

(vl-string-trim (apply 'strcat (wildcard-trim "~#")) str)

Évidemment, avec la fonction (vl-string-trim) cela permet uniquement de supprimer les caractères en partant de la gauche et de la droite, jusqu'à ce qu'un caractère autorisé soit trouvé. Autrement dit, pour une chaîne de caractère telle que

(setq str "ma80cm")
;; ou
(setq str "Surface = 42.23m (+NGF)")
;; etc...

On obtient respectivement les résultats :

"80"
;; ou
"42.23"

Mais comme le souligne @bonuscad, dans le cas d'un nombre négatif, le moins est supprimé donc il y a une perte d'information dans ce cas-ci. Autre limite : dans le cas où il y a deux valeurs numériques dans une même chaîne de caractères, comme par exemple

(setq str "Value = -543.1530054 (equals to 2u)")

(vl-string-trim (apply 'strcat (wildcard-trim "~#")) str) returns
"543.1530054 (equals to 2"

Bref, cela réponds à un problème simple dans les conditions établies, mais cela possède ses propres limites tout de même si l'on étend son utilisation en dehors des conditions actuelles. Par contre, les nombres décimaux sont conservés correctement 😉

Bisous,
Luna

Lien vers le commentaire
Partager sur d’autres sites

Pour capturer un ou plusieurs nombres, entiers ou réels, négatifs ou positifs, j'utiliserais les expressions régulières.

(defun getFirstNumber (str)
  (caar (RegExpExecute str "(-?\\d+(?:\\.\\d+)?)" nil nil))
)

(defun getAllNumbers (str)
  (mapcar 'car (RegExpExecute str "(-?\\d+(?:\\.\\d+)?)" nil T))
)

_$ (getFirstNumber "Ma80cm")
"80"
_$ (getFirstNumber "Surface = 42.23m (+NGF)")
"42.23"
_$ (getAllNumbers "Surface = 42.23m² Température = -4°C")
("42.23" "-4")

Petite explication du motif (pattern) utilisé :

( 	 	début de groupe capturé
-?      	zero ou un -
\\d+		un ou plusieurs chiffres
(?:		début de groupe non capturé
\\.\\d+		un point suivi de un ou plusieurs chiffres
)		fin de groupe non capturé
?		zero ou un groupe
)		fin de groupe capturé

 

  • Like 1

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

J'avais en effet supposé que les expressions régulières seraient parfaite pour faire ce genre de travail !! Mais comme je n'ai toujours pas eut le temps d'étudier le sujet, je ne les maîtrise pas (notamment à cause des caractères de recherche qui diffèrent des WildCard Characters donc mon cerveau n'est pas encore suffisamment habitué)...

Mais il va sérieusement falloir que je passe du temps à étudier toutes ces notions encore un peu trop obscures à mes yeux, parce que j'ai l'impression de faire du surplace en programmation pour le moment et j'aime pas trop chat...

Merci pour cet exemple @(gile) !

Bisous,
Luna

Lien vers le commentaire
Partager sur d’autres sites

Autre solution possible de la part d'un développeur fainéant :

1) afficher la chaine de caractère "Ma80cm"
2) demander à l'utilisateur les caractères qu'il veut isoler
3) vérifier avec wcmatch, si ok étape 4 sinon retour étape 1
4) suite du programme

On a bien dit que tous les chemins mènent à Rome, non ? 😇

Lien vers le commentaire
Partager sur d’autres sites

Le 29/01/2022 à 18:46, DenisHen a dit :

Bonjour à la communauté.

Voilà, je dois trouver le chiffre unique contenu dans une chaine, par exemple, dans "Ma80cm", j'aimerais isolé 80.

Si quelqu'un a une astuce, un bout de code, une idée... Je suis preneur...

Bien à toi la communauté.

Denis...

Bonjour,

Si tu es sur que ta chaîne ne contient que des caractères AlphaNumérique, tu peux très simplement tenter ceci:

_$ (vl-string-trim "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (strcase "Ma80cm"))
"80"
_$ (vl-string-trim "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (strcase "80Macm"))
"80"
_$ (vl-string-trim "ABCDEFGHIJKLMNOPQRSTUVWXYZ" (strcase "Macm80"))
"80"

Cdt Bruno

(Ps: Sinon il y a évidement les expressions régulières mentionné par (gile) beaucoup plus puissante..)

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Le 29/01/2022 à 21:39, (gile) a dit :

Donc, tant que le premier caractère de la chaine en entrée n'est pas un chiffre, on supprime le premier caractère de la chaine en entrée.
Puis, tant que le premier caractère de la chaîne de la chaine en entrée est un chiffre, on ajoute ce caractère à la fin de la chaîne en sortie et on supprime le premier caractère de la chaine en entrée.

Et pour le jeu en traduisant récursivement l’algorithme donné par (gile), ça peut donner ceci:

(defun f (s)
    (cond ((= s "") "")
      ((wcmatch (substr s 1 1) "#") (strcat (substr s 1 1) (f (substr s 2))))
      (T (f (substr s 2)))
    )
  )

 

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Il y a 2 heures, VDH-Bruno a dit :

Et pour le jeu en traduisant récursivement l’algorithme donné par (gile), ça peut donner ceci:

Pas tout à fait, je disais "Puis, tant que le premier caractère ..." et ta routine évalue toute la chaîne même si les derniers caractères ne sont pas de chiffres.

On pourrait utiliser un argument à T ou nil pour s'arrêter au dernier chiffre trouvé:

(defun f (s p)
  (cond	((= s "") "")
	((wcmatch (substr s 1 1) "#") (strcat (substr s 1 1) (f (substr s 2) T)))
	(p "")
	(T (f (substr s 2) p))
  )
)

_$ (f "Ma80cm" nil)
"80"

Gilles Chanteau - gileCAD - GitHub
Développements sur mesure pour AutoCAD

Lien vers le commentaire
Partager sur d’autres sites

il y a une heure, (gile) a dit :

Pas tout à fait, je disais "Puis, tant que le premier caractère ..." et ta routine évalue toute la chaîne même si les derniers caractères ne sont pas de chiffres.

Oui tu as raison, je me suis fait prendre par la patrouille, en première intention je voulais écrire une fonction auxiliaire pour ne pas parcourir toute la chaîne, puis comme c'était à titre d'exemple j'ai sacrifié l'efficience à la concision pensant que personne ne le verrais... 😂

il y a une heure, (gile) a dit :
  Il y a 3 heures, VDH-Bruno a dit :

Et pour le jeu en traduisant récursivement l’algorithme donné par (gile), ça peut donner ceci:

D’ailleurs comme j'avais mauvaise conscience, j'ai voulu me dédouaner en précisant "ça peut donner"😂😂😂

Oui il y avait une petite escroquerie, je te remercie de l'avoir relevée😉

Apprendre => Prendre => Rendre

Lien vers le commentaire
Partager sur d’autres sites

Créer un compte ou se connecter pour commenter

Vous devez être membre afin de pouvoir déposer un commentaire

Créer un compte

Créez un compte sur notre communauté. C’est facile !

Créer un nouveau compte

Se connecter

Vous avez déjà un compte ? Connectez-vous ici.

Connectez-vous maintenant
×
×
  • Créer...

Information importante

Nous avons placé des cookies sur votre appareil pour aider à améliorer ce site. Vous pouvez choisir d’ajuster vos paramètres de cookie, sinon nous supposerons que vous êtes d’accord pour continuer. Politique de confidentialité