Terminal: MacBook Air OS: macOS High Sierra Swift: 4.0.3 (swiftlang-900.0.74.1 clang-900.0.39.2) Clang: Apple LLVM version 9.0.0 (clang-900.0.39.2)
Je pense que tout le monde utilise avec désinvolture la méthode suivante lors de la conversion d'une chaîne C (char \ *) en une chaîne Swift ou Objective-C (String, NSString).
String.swift
init?(cString: UnsafePointer<CChar>) //typealias CChar = Int8
Tout d'abord, je voudrais présenter le cString qui est passé à cette méthode, c'est-à-dire la chaîne C. Ensuite, en fait, la méthode ci-dessus a été abolie du côté NSString, et une méthode pour spécifier le codage en même temps est préparée comme indiqué ci-dessous. Je voudrais réfléchir à la valeur d'encodage passée à ce moment.
String.swift
init?(cString: UnsafePointer<CChar>, encoding enc: String.Encoding)
«Char» est fourni comme un type qui représente un caractère en langage C. Une valeur de 1 octet peut être stockée dans cette variable de type char. La lettre C entoure la lettre entre guillemets simples. Et la valeur entre guillemets simples est appelée littéral de caractère.
Lettre C.c
int main(void) {
char c = '*'; //「'Il est converti en une valeur ASCII 1 octet en entourant le caractère d'une "marque".
printf("%c\n", c); // *
printf("%ld\n", sizeof(c)); // 1
}
Comme mentionné dans les commentaires, ce qui précède est en fait la syntaxe d'enrobage de sucre suivante.
lettre c.c
int main(void) {
char c = 42;
printf("%c\n", c); // *
printf("%ld\n", sizeof(c)); // 1
}
En d'autres termes, la substance du caractère littéral est "juste un nombre".
De plus, si vous mettez des caractères multi-octets entre guillemets simples comme indiqué ci-dessous, le nombre généré (* 1) dépassera la taille de char
(1 octet), ce qui entraînera une erreur de compilation.
(\ * 1: Pour la valeur générée, consultez la section ci-dessous "[Lorsque des caractères multi-octets sont stockés dans la chaîne C](https://qiita.com/ysn551/items/446074b22103233edd95#c%E3%81] % AE% E6% 96% 87% E5% AD% 97% E5% 88% 97% E3% 81% AB% E3% 83% 9E% E3% 83% AB% E3% 83% 81% E3% 83% 90 % E3% 82% A4% E3% 83% 88% E6% 96% 87% E5% AD% 97% E3% 82% 92% E6% A0% BC% E7% B4% 8D% E3% 81% 97% E3 % 81% 9F% E5% A0% B4% E5% 90% 88) ”)
Lettre C.c
//Ce fichier de code source est enregistré en UTF8
int main(void) {
char c = 'Ah'; // error: character too large for enclosing character
}
En d'autres termes, les caractères multi-octets ne peuvent pas être stockés car ils le sont dans des variables de type char.
De plus, la vérification que le littéral de caractère réel est un nombre à 1 octet peut être prouvée par le fait que la valeur peut être directement stockée dans le type int (4 octets) comme indiqué ci-dessous.
La substance du caractère littéral est un nombre de 1 octet.c
int main(void) {
int num = 'abcd';
printf("%0x\n", num); // 64656667
}
Le résultat de la sortie de la valeur de num en hexadécimal est "64656667", et si vous lisez la valeur en unités d'octets, vous pouvez voir qu'elle peut être décomposée en "64,65,66,67".
char
char
est une boîte pour stocker des valeurs à 1 octetchar
, qui contient un nombre (valeur d'encodage)La chaîne de langage C est un tableau de type «char». En d'autres termes, il est représenté par un tableau pour stocker des données à 1 octet. En outre, la chaîne de caractères C entoure le caractère entre guillemets. En outre, la valeur entre guillemets est appelée littéral de chaîne.
C chaîne.c
int main(void) {
char str[] = "Hello"; //Le nombre d'éléments peut être omis en initialisant en même temps.
printf("sizeof(str)/sizeof(char) = %ld\n", sizeof(str)/sizeof(char)); // 6
}
La chaîne de caractères * Hello * utilisée pour l'initialisation ci-dessus est de 5 caractères, mais le nombre d'éléments est de 6. En fait, il a la syntaxe d'enrobage de sucre suivante.
À propos de la chaîne de caractères de C.c
int main(void) {
char str[] = {'H','e','l','l','o','\0'};
printf("sizeof(str)/sizeof(char) = %ld\n", sizeof(str)/sizeof(char)); //6
}
En d'autres termes, la chaîne de caractères littérale "" Hello "` renvoie un tableau de caractères avec 6 éléments qui stocke le caractère nul à la fin.
char
Bien que cela ne soit pas mentionné dans la section ci-dessus, les résultats lorsque le code source initialisé avec des caractères multi-octets comme indiqué ci-dessous est enregistré dans un fichier avec UTF8 et lorsqu'il est enregistré dans un fichier avec Shift-JIS sont affichés ci-dessous. J'aimerais voir ça.
À propos de la chaîne de caractères de C.c
int main(void) {
char str[] = "Ah"; //Si vous déclarez un tableau en même temps que l'initialisation, vous pouvez omettre le nombre d'éléments
int size = sizeof(str);
for (int i = 0; i < size; i++) {
printf("%hhx ", str[i]); //Validez cette sortie à chaque encodage
}
}
Méthode de vérification:
Sortie lors de l'enregistrement en UTF8:
case_utf8_result.txt
e3 81 82 0
Sortie lors de l'enregistrement sous Shift-JIS:
case_shift_jis_result.txt
82 a0 0
Pour chacune des valeurs ci-dessus, entrez «A» dans ce Site et affichez le résultat. résultat
En d'autres termes, vous pouvez voir que le résultat du littéral de chaîne du caractère multi-octets en langage C correspond au codage de l'éditeur de texte.
C'est un résultat très naturel car nous transmettons le "fichier" dans lequel le code source est écrit au compilateur, pas le "code source".
En d'autres termes, dans le cas de l'UTF8, on peut dire que char str [] =" a "
est la syntaxe d'enrobage de sucre suivante.
À propos de la chaîne de caractères de C.c
int main(void) {
//e3 81 82 0
char str[] = {0xe3, 0x81, 0x82, 0x0};
printf("%s \n", str); //Si le paramètre de codage du terminal est UTF8, "A" s'affiche.
}
Si le terminal à exécuter ci-dessus est codé en UTF-8 et exécuté, "A" s'affiche. Si vous utilisez Shift-JIS, les caractères seront déformés. (Paramètres → Profils → Balise avancée)
Par conséquent, le haut est le résultat lorsque Shift-JIS est défini et le bas est le résultat lorsque UTF8 est défini.
Je voudrais utiliser l'API Swift ci-dessous pour convertir les caractères passés de l'API C en une chaîne Swift. Quelle devrait être la valeur de codage spécifiée à ce moment?
String.swift
init?(cString: UnsafePointer<CChar>, encoding enc: String.Encoding) //CChar = Int8
Le code de programme C à vérifier est le suivant.
libc.c
char* file_name() {
return "hello.txt";
}
char* new_file_header_str() {
FILE *f = fopen(file_name(), "r");
if (f == NULL) return NULL;
char *str = calloc(256, sizeof(char));
fgets(str, 256, f); //Une seule ligne
fclose(f);
return str;
}
Lors de l'appel de ce qui précède depuis Swift, le type C char *
est passé en tant que type ʻUnsafeMutablePointer
Tout d'abord, je voudrais vérifier que le caractère C obtenu à partir de la fonction nom_fichier
est converti en caractère Swift.
Ce littéral de chaîne de caractères est renvoyé tel quel.
En d'autres termes, vous pouvez voir que la valeur d'encodage lors de la conversion en une chaîne Swift doit être la même que l'encodage dans le fichier libc.c.
Ensuite, qu'en est-il de la valeur de codage utilisée pour convertir le caractère C obtenu à partir de la fonction new_file_header_str
en une chaîne de caractères Swift?
Ici, la chaîne de caractères du fichier hello.txt
est renvoyée.
Ainsi, vous pouvez voir que la valeur d'encodage que vous devez spécifier ici doit être la même que la valeur d'encodage où le fichier hello.txt
est stocké.
Vous trouverez ci-dessous un exemple de code source qui enregistre le fichier lib.c en UTF-8 et le fichier hello.txt en Shift-JIS et appelle chaque fonction depuis Swift.
get_str_from_c.swift
let name = file_name() //Optional<UnsafeMutablePointer<Int8>>
if let name = name,
let converted = String(cString: name, encoding: .utf8) {
print(converted)
}
let header = new_file_header_str() //Optional<UnsafeMutablePointer<Int8>>
if let header = header,
let converted = String(cString: header, encoding: .shiftJIS) {
print(converted)
}
Veuillez vous référer à ce qui suit pour appeler la bibliothèque C. https://qiita.com/ysn551/items/83e06cf74ae628cb573c
De cette façon, le littéral de chaîne C stocke directement la valeur de codage, donc cela dépend de l'environnement de développement. D'ailleurs, dans le cas du compilateur Swift, seuls les fichiers UTF8 peuvent être compilés.
En revanche, dans Python3, la valeur générée par le littéral de chaîne est un nombre, mais il s'agit d'une valeur Unicode. Par conséquent, il n'est pas nécessaire de prendre en compte le codage lors de l'échange de littéraux de chaîne entre fichiers.
Le résultat de la vérification avec python3 est le suivant. À propos, Python2 utilise des valeurs d'encodage, il est donc inutile si l'encodage entre les codes sources est différent.
Enregistrez le fichier shift_jis.py suivant dans l'encodage Shift-JIS
shift_jis.py
#! coding=shift-jis
word = "Ravi de vous rencontrer"
Enregistrez le fichier utf8.py suivant sous le nom UTF8 et exécutez-le.
utf8.py
#! coding=utf-8
import shift_jis as sh
if sh.word == "Ravi de vous rencontrer":
print("true")
else:
print("false")
Lorsque j'exécute ce qui précède sur python3, true s'affiche, mais sur python2, false s'affiche.
J'ai hâte de travailler avec vous en 2018. m (__) m
Recommended Posts