Aller au contenu

Manipuler des strings


Messages recommandés

Yo !

 

Je ne sais pas encore bien interpréter la doc Apple officielle et je souhaiterais avoir 2-3 trucs de base pour manipuler des strings comme par exemple :

 

- Trouver une chaîne de caractère précise dans un string (ou juste savoir si sa présence est vraie ou fausse).

- Remplacer une partie du texte par un autre dans un string

- Compter le nombre de caractères dans un string

- Enlever les espaces ne servant à rien dans un début de string (équivalent au trim de Xojo)

 

 

Je tâtonne encore pas mal mais chaque trouvaille est une petite victoire :zz-big-back:

 

Là je commence à essayer de transposer du code Xojo en Objective-C et je sens bien que certaines bases sont manquantes mais je progresse :zz-big-candidat:

 

 

Merci de votre aide.

Lien à poster
Partager sur d’autres sites

Alors :

- Trouver une chaîne de caractère précise dans un string (ou juste savoir si sa présence est vraie ou fausse).

 

​Il faut chercher avec "[maString rangeOfString:maRecherche]". Ça te renvois un NSRange qui est une structure avec deux champs : location et length. Si la chaine est trouvée, ça contiens respectivement l'index de maRecherche dans maString et la taille de maRecherche. Si la chaine est non trouvé, alors location == NSNotFound et length == 0 (habituellement on test just location)

 

La doc dit à propos du retour : "An NSRange structure giving the location and length in the receiver of the first occurrence of aString. Returns {NSNotFound, 0} if aString is not found or is empty (@"")."

 

- Remplacer une partie du texte par un autre dans un string

 

Je sais pas si tu as assimilé le côté mutable / immutable de pas mal de collection en Cocoa. Par exemple NSString est immutable (le contenus ne peut pas être changé après création) et NSMutableString est mutable (sont contenus peut être changé après création).

 

Pour remplacer un texte par un autre dans une chaine, il faut la modifier, donc il te faut une NSMutableString (tu peut faire un mutableCopy sur ta string pour en avoir une copie mutable).

 

La méthode à utiliser est "[maString replaceOccurrencesOfString:maStringOrigine withString:maStringRemplace options:0 range:NSMakeRange(0, [maString length])]"

 

- Compter le nombre de caractères dans un string

"[maString length]"

 

- Enlever les espaces ne servant à rien dans un début de string (équivalent au trim de Xojo)

 

"[maString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]"

 

Sachant que cette méthode n'existe que dans NSString et pas dans NSImmutableString, la chaine trimé est une nouvelle instance de NSString qui est renvoyé.

 

Tu peut faire un truc du genre : "maString = [maString stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]"

 

Elle prend en paramètre un set (un array non ordonné) de caractère à trimer. Il y a un certain nombre de set pré-disponible (cf la doc de NSCharacterSet) dont un set contenant les caractère d'espacement.

Lien à poster
Partager sur d’autres sites

La vaaache !

 

Merci beaucoup Jipé, explications très claires comme d'hab…

 

Effectivement je n'avais pas capté la notion de mutable et immutable et j'aurais rencontré un sérieux souci en voulant faire comme avec Xojo (dur de se séparer de certains réflexes voir, réflexions)…

 

En Xojo, tu peux dire qu'un string est toujours ce même string mais amputé de certains caractères, on est donc dans un système mutable de string par défaut si j'ai bien tout suivi.

 

Bon je vais essayer de continuer cet aprem mais si je n'ai pas au moins 2h00 devant moi, je ne me lance pas sinon je m'embrouille et je veux avoir le temps de bien faire (ou de bien comprendre)…

 

Merci encore… :zz-big-bien:

… et à bientôt :zz-big-army:

Lien à poster
Partager sur d’autres sites

Yep. Avoir des conteneurs mutables / immutables à pas mal d'avantages en fait. Autre le fait que les versions mutables sont souvent plus optimales que les versions immutables (détail d'implémentation), ça permet une certaine rigueur au niveau de la programmation.

Par exemple quand une méthode de classe renvoie une NSString qui est une variable d'instance, si on n’avait pas le choix de la mutabilité, alors pour respecter le principe d'encapsulation, on devrait toujours créer une copie de notre variable (car sinon l'utilisateur de la classe pourrais changer le contenu d'une variable interne ce qui n'est pas bon) - ça impliquerait une perte de performance pour rien. Avec le fait qu’elle soit immutable, on peut renvoyer une variable interne : on a la garantie que c'est safe, sans être obligé de faire de copie.

C'est aussi utile en contexte multithreadé (ça devient de plus en plus courant avec la libdispatch) : on sait que quand on manipule des immutables, on n’a pas besoin de se soucier de la synchronisation. Autant de thread qu'on veut peuvent accéder à l'objet en parallèle sans soucis : vu que l'objet n'est jamais changé, il n'y a pas de soucis.

En général on expose des conteneurs immutables. Les mutables sont plutôt utilisés dans le code interne d'une classe.

Lien à poster
Partager sur d’autres sites

OUi je vois bien l'intérêt effectivement… L'objet original garde toujours sa valeur première et unique, on sait donc de quoi on part sans ce soucier du risque qu'une méthode modifie cet objet dynamiquement foutant en l'air le fait qu'on pense connaître le contenu qui n'a plus rien à voir avec l'original…

Lien à poster
Partager sur d’autres sites

Bon voici mon code (et qui fonctionne svp !) pour rechercher un mot dans une chaîne de caractères si ça peut servir à d'autres :

// déclaration des variables pour la recherche
NSString *Test1 = @"ceci est un test pour trouver le mot oui";
NSString *MotAChercher = @"oui";
NSRange *RetourdeTest1;

 

Code de mon bouton qui déclenche l'action :

- (IBAction)BoutonOui:(id)sender {
NSRange RetourdeTest1= [Test1 rangeOfString:MotAChercher];
if(RetourdeTest1.location != NSNotFound) {
NSLog(@"trouvé");
}
}

 

Là où je me suis fait avoir c'est que je ne pensais pas devoir redire dans mon bouton que RetourTest1 et toujours un NSRange alors que je l'avais déjà déclaré en tant que tel plus haut…

 

Et un truc idiot : j'avais déclaré mes variables dans la méthode :

 

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
}

Donc forcément elles n'étaient plus accessibles pour le code de mon bouton et là, j'ai un peu cherché pour le coup ! :zz-big-dingue:

Lien à poster
Partager sur d’autres sites

Deux choses :

- NSRange est bien une structure C et non pas une classe Cocoa (oui c'est traitre). Même si ça n'est pas faux de déclarer un NSRange en pointeur (avec le * devant le nom de variable), c'est assez rare. La plupart du temps on le déclare comme un type simple (c'est à dire sans le * devant le nom de variable - à la manière d'un NSInteger par exemple). D'ailleurs "rangeOfString" renvois bien une structure simple, pas un pointeur.

Tu n'as pas à redéfinir le type de ta variable de classe dans ton IBAction (d'ailleurs ce que tu as fait ne consiste pas à redéfinir le type, mais à une nouvelle déclaration de variable : elle n'a absolument rien à voir avec la variable de classe. C'est possible en C d'avoir un recouvrement de nom de variable comme ça, mais c'est déconseillé, car on s'y perd vite. La variable retenue est celle qui est la plus "proche" - on parle de scope).

- Par habitude on déclare les variables de classe avec un _ devant le nom : ça permet de distinguer plus rapidement à la lecture de code ce qui est une variable locale et ce qui est une variable de classe.

 

[Edit]

P.-S. Je ne sais pas si tu as capté la notion de pointeur en C. C'est peut-être un peu long à expliquer - pour commencer ce qu'il faut retenir, c'est que les pointeurs sont des références vers une instance (c’est-à-dire une valeur, un objet, etc.) de "quelque chose" (c’est à dire une classe, structure, entier, etc.). Ça permet de partager une même instance via plusieurs variables, et via appel / retour de méthode. Les instances de classe Objective-C ne peuvent être référencées que par des pointeurs (tu ne verras jamais un "MaClasse monInstance;" - tu verras toujours forcément des "MaClasse *monInstance;". Je vais pas rentrer dans les détails du pourquoi, juste que c'est une question de tas, de stack, de référence counting et de dynamisme.

NSRange n'étant pas une classe, ses instances peuvent être référencées via pointeur ou directement (comme pour des NSInteger). La plupart du temps ils sont référencés directement (et donc non partagé : si une instance est passée en paramètre d’une méthode, la méthode recevra une copie - comme pour un NSInteger).

Lien à poster
Partager sur d’autres sites

De quoi ? Les pointeurs ou les recherches dans les strings ? Honnêtement les pointeurs, quand on fait de l'Objective-C on ne s’en occupe pas dans 95% du temps. Il y a peut être deux cas où cette notion se voit : pour des structures genre NSRect, NSSize, NSRange, et pour les retours d'erreur NSError.

 

Après niveau syntaxe, ce n’est pas la mort. C’est plus verbeux sur les méthodes et un peu moins sur le langage, mais après ça reste similaire. Une fois franchie la première marche (la plus difficile) des différences majeures, ça roule assez bien.

Le plus important, c'est de ne pas se laisser impressionner par l'ensemble des différences entre les deux mondes. Il suffit d'y aller petit bout par petit bout.

 

Je rentre peut être dans les détails, mais juste se contenter d'apprendre la leçon peut suffit, genre "Classes : * / NSRange : pas de *" et puis voilà :P

De mémoire il me semble qu'il y a le même genre de notion avec "ByRef" sous RB.

Lien à poster
Partager sur d’autres sites

Oui j'ai vu des exemples avec le fameux "_" devant le nom… Je me suis douté que c'était une nomenclature particulière car je les ai retiré partout et le code continuait de fonctionner normalement…

 

Merci pour l'explication des pointeurs… Il est vrai que j'ai pas mal de lacunes et que je suis preneur de tout ce que tu pourras m'expliquer sur les notions (de base ou pas d'ailleurs)…

 

Par contre j'ai retiré le NSRange devant "retourTest1" dans mon action de bouton et j'ai un message d'erreur à la compilation…

 

Le hamster : je te comprends mais je m'accroche… Et j'avoue que je me demande si je ne commence pas à y prendre goût…

Lien à poster
Partager sur d’autres sites

Le block "déclaration des variables pour la recherche" se trouve où au juste ? Je pense que c'est ça qui me perturbe. D'un côté tu déclare un variable "RetourdeTest1" et de l'autre tu re-déclare cette variable dans tes IBAction.

Lien à poster
Partager sur d’autres sites

Ha ok j'ai compris ce matin après une nuit de repos, je n'avais pas besoin de faire la première déclaration (celle où il y a avait un pointeur justement)…

 

Pour info ma déclaration de variables est juste après mon "@implementation AppDelegate" et les "@synthesize"… Donc au début de mon fichier .h

Lien à poster
Partager sur d’autres sites

Deux choses :

-> Sur la distinction .h / .m :

Quand Xcode compile ton projet, il passe en revue les différents fichiers qui y sont inclus, et y applique des traitements en fonction du type de fichier. Les traitements à effectuer sont définis dans la partie "Build Rules" (c'est très rare qu'on ait à y toucher). Par exemple, les .strings sont tous convertis en UTF16, les PNG convertis sur iOS, les fichiers .xib sont optimisés, les fichiers .m sont compilés, etc.

Il n'y a aucune règle pour les fichiers .h : ce sont des fichiers "inactifs" qui ne sont traités par personne. Ils ne sont vus que quand ils sont inclus (que ce soit directement ou indirectement via un autre .h) dans un .m : au moment de la compilation du .m. En fait, ils n'ont même pas de contenus "actif" (c'est à dire du code par exemple) : ils ne servent qu'à décrire quelque chose (un type, une classe via une interface, etc.). C'est une aide au compilateur quand il traite un .m pour savoir que telle ou telle classe existe, quelle as telle ou telle méthode, et éventuellement telle ou telle variable (quoi qu'avec Objective-C 2.0 et l'ABI 64 bits on expose plus les variables dans les headers).

Il ne doit pas y avoir de contenus "actifs" dedans, car un header peut être inclus dans plusieurs .m, et donc être traités plusieurs fois. S’il y avait du contenu actif, alors ce contenu serait présent plusieurs fois dans le produit fini, et générerait des conflits.

Tout ça pour dire que:

- Dans un .h, tu ne dois pas avoir de "@implementation" : tu doit avoir que du contenus "inactif" / "descriptif" par exemple des déclarations de type, des interfaces de classe (@interface), etc. Que des choses qui aident le compilateur, mais qui n'ont pas de réalité concrète dans le produit final.

- Dans un .m, tu peut tout avoir (ce qui est logique vu qu'on inclut des .h avec du contenu inactif dedans) : du contenu "actif" (du code source déclaré dans le @implementation) comme du contenu "inactif" / "descriptif" (comme des interfaces déclarées dans le @interface).

-> Sur les @synthetize

Il n'y a plus nécessité de mettre de @synthetize, et de déclarer ta variable liée à ton @property quand tu utilises Objective-C 2.0 (c'est forcément le cas avec Xcode 4) + ABI 64 bits (c'est très probablement le cas).

Lien à poster
Partager sur d’autres sites

Clair et encore une fois : merci :zz-big-bien:

 

En fait je l'avais fait z-exprès bien entendu pour que les autres puissent avoir l'explication de Jipé… Merci qui ? :cool2:

Lien à poster
Partager sur d’autres sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Invité
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

Chargement
×
×
  • Créer...