C
Mon devoir est de prendre une chaîne et de la diviser en morceaux à chaque nouvelle ligne. Je ne sais pas quoi faire! Aidez-moi!
Problème délicat pour une classe de programmation C débutante! Vous devez d'abord comprendre quelques notions de base sur ce sujet compliqué.
Une chaîne est une séquence composée uniquement de caractères . Cela signifie que pour que les programmeurs indiquent une chose "invisible" (ce n'est pas un espace, qui compte comme un caractère), vous devez utiliser une séquence spéciale de caractères pour signifier cette chose invisible.
Sous Windows , la nouvelle ligne est une séquence de deux caractères dans la chaîne: barre oblique inverse et n (ou la chaîne "\n"
)
Sous Linux ou Mac OS / X , il s'agit d'une séquence de quatre caractères: barre oblique inverse, n, barre oblique inverse, puis r: (ou "\n\r"
).
(Note historique intéressante: sur les Macintoshes plus anciens, c'était une séquence différente de quatre caractères: "\ r \ n" ... totalement en arrière par rapport à la façon dont Unix faisait les choses! L'histoire prend des routes étranges.)
Il peut sembler que Linux est plus gaspilleur que Windows, mais c'est en fait une meilleure idée d'utiliser une séquence plus longue. Étant donné que Windows utilise une séquence aussi courte, le runtime du langage C ne peut pas imprimer les lettres réelles \n
sans utiliser d'appels système spéciaux. Vous pouvez généralement le faire sous Linux sans appel système (il peut même imprimer \n\
ou \n\q
... tout sauf \n\r
). Mais puisque C est censé être multiplateforme, il applique le plus petit dénominateur commun. Vous verrez donc toujours \n
dans votre livre.
(Remarque: si vous vous demandez comment nous parlons \n
sans obtenir de nouvelles lignes à chaque fois que nous le faisons, StackOverflow est écrit presque entièrement en HTML ... pas C. Donc c'est beaucoup plus moderne. Beaucoup de ces anciens aspects de C sont être abordé par des choses dont vous avez peut-être entendu parler, comme CLANG et LLVM.)
Mais revenons à ce sur quoi nous travaillons. Imaginons une chaîne avec trois pièces et deux sauts de ligne, comme:
"foo\nbaz\nbar"
Vous pouvez voir que la longueur de cette chaîne est 3 + 2 + 3 + 2 + 3 = 13. Vous devez donc créer un tampon de longueur 13 pour cela, et les programmeurs C en ajoutent toujours un à la taille de leurs tableaux pour être sûr. Faites donc votre tampon et copiez-y la chaîne:
/* REMEMBER: always add one to your array sizes in C, for safety! */
char buffer[14];
strcpy(buffer, "foo\nbaz\nbar");
Maintenant, ce que vous avez à faire est de rechercher ce modèle à deux caractères qui représente la nouvelle ligne. Vous n'êtes pas autorisé à rechercher juste une barre oblique inverse. Parce que C est beaucoup utilisé pour le fractionnement de chaînes, il vous donnera une erreur si vous essayez. Vous pouvez le voir si vous essayez d'écrire:
char pattern[2];
strcpy(pattern, "\");
(Remarque: Il y a un paramètre dans le compilateur pour si vous écrivez un programme qui ne recherche que des antislashs. Mais c'est extrêmement rare; les antislashs sont très rarement utilisés, c'est pourquoi ils ont été choisis à cet effet. Nous ne tournerons pas cela allumer.)
Faisons donc le modèle que nous voulons vraiment, comme ceci:
char pattern[3];
strcpy(pattern, "\n");
Lorsque nous voulons comparer deux chaînes d'une certaine longueur, nous utilisons strncmp
. Il compare un certain nombre de caractères d'une chaîne potentiellement plus grande et vous indique s'ils correspondent ou non. Renvoie donc strncmp("\nA", "\nB", 2)
1 (vrai). C'est même si les chaînes ne sont pas entièrement égales sur la longueur de trois ... mais parce que seulement deux caractères sont nécessaires.
Passons donc en revue notre tampon, un caractère à la fois, en recherchant la correspondance de deux caractères avec notre modèle. Chaque fois que nous trouvons une séquence à deux caractères d'une barre oblique inverse suivie d'un n, nous utiliserons l' appel système très spécial (ou "syscall") putc
pour émettre un type spécial de caractère: le code ASCII 10 , pour obtenir une nouvelle ligne physique .
#include "stdio.h"
#include "string.h"
char buffer[14]; /* actual length 13 */
char pattern[3]; /* actual length 2 */
int i = 0;
int main(int argc, char* argv[]) {
strcpy(buffer, "foo\nbar\nbaz");
strcpy(pattern, "\n");
while (i < strlen(buffer)) {
if (1 == strncmp(buffer + i, pattern, 2)) {
/* We matched a backslash char followed by n */
/* Use syscall for output ASCII 10 */
putc(10, stdout);
/* bump index by 2 to skip both backslash and n */
i += 2;
} else {
/* This position didn't match the pattern for a newline */
/* Print character with printf */
printf("%c", buffer[i]);
/* bump index by 1 to go to next matchable position */
i += 1;
}
}
/* final newline and return 1 for success! */
putc(10, stdout);
return 1;
}
La sortie de ce programme est le résultat souhaité ... le split de chaîne!
foo
baz
bar
\t
est pour \ trolling ...
Absolument incorrect de haut en bas. Pourtant, rempli de bêtises à consonance plausible qui ont brouillé des informations comme ce qui est dans le manuel ou Wikipedia. La logique du programme apparaît transparente dans le contexte de la désinformation, mais est complètement trompeuse. Même des variables globales et renvoyant un code d'erreur, pour faire bonne mesure ...
...
Bien sûr, il n'y a qu'un seul caractère dans la représentation de chaîne C de la séquence littérale source à deux caractères \n
. Mais agrandir un tampon est inoffensif, tant qu'il strlen()
est utilisé pour obtenir la longueur réelle à utiliser.
...
Nous essayons de convaincre le lecteur qu'il strncmp
s'agit d'une opération booléenne qui correspond à (1) ou non (0). Mais il a en fait trois valeurs de retour (-1 correspondant moins, 0 pour égal, 1 pour correspondre plus) . Notre "motif" à deux caractères comparé n'est pas [ \
, n
], mais plutôt [ \n
, \0
] ... en prenant le terminateur nul implicite. Au fur et à mesure que cette séquence glisse dans la chaîne, elle ne sera jamais supérieure à une séquence de deux caractères à laquelle elle est comparée ... au mieux, elle sera nulle s'il y a une nouvelle ligne de fin dans la chaîne d'entrée.
...
Donc, tout cela ne fait que parcourir la chaîne et l'imprimer un caractère à la fois. La branche supérieure ne s'exécute jamais. (Bien que vous puissiez y accéder si votre chaîne \n
contient des codes inférieurs à, dites tab ... qui pourrait être utilisé pour omettre mystérieusement des caractères de la sortie :-P)