Tâche
Étant donné une chaîne UTF-8 (par tous les moyens), répondez (par tous les moyens) à une liste équivalente où chaque élément est le nombre d'octets utilisés pour coder le caractère d'entrée correspondant.
Exemples
!
→ 1
Ciao
→ 1 1 1 1
tʃaʊ
→ 1 2 1 2
Adám
→ 1 1 2 1
ĉaŭ
→ 2 1 2
(caractères uniques)
ĉaŭ
→ 1 2 1 1 2
(utilise la combinaison de superpositions)
チャオ
→ 3 3 3
(entrée vide) →
(sortie vide)
!±≡𩸽
→ 1 2 3 4
(un octet nul) → 1
Octets nuls
Si la seule façon de continuer à lire les entrées au-delà des octets nuls est de connaître le nombre total d'octets, vous pouvez obtenir le nombre d'octets par n'importe quel moyen (même une entrée utilisateur).
Si votre langue ne peut pas du tout gérer les octets null, vous pouvez supposer que l'entrée ne contient pas de null.
Réponses:
Pyth,
97 octetsMerci à @Maltysen d'avoir économisé 2 octets!
Suite de tests
Convertit chaque caractère de l'entrée en sa représentation binaire, puis le divise en morceaux de longueur 8. Le nombre de ces morceaux est alors la quantité d'octets nécessaires pour coder ce caractère.
la source
.E
pyth.herokuapp.com/…mlhc8.B
ml%8.B
(maintenantd
c'est implicite).Python 3,
4236 octetsla source
map
.lambda x:map(len,map(str.encode,x))
C,
6865 octetsMerci à @FryAmTheEggman pour avoir joué au golf sur 3 octets!
Testez-le sur Ideone .
la source
APL, 15 caractères
En anglais: convertissez chaque caractère en UTF-8 (ce qui signifie: vecteur de représentation des octets) et obtenez son décompte.
la source
≢¨'UTF-8'∘⎕ucs¨
+⌿0 7 11 16∘.≤2⍟⎕UCS
0 7 11 16⍸2⍟⎕UCS
GolfScript, 16 octets
Essayez-le en ligne!
Contexte
GolfScript n'a aucune idée de ce qu'est Unicode; toutes les chaînes (entrée, sortie, interne) sont composées d'octets. Bien que cela puisse être assez ennuyeux, il est parfait pour ce défi.
UTF-8 code différemment les caractères ASCII et non ASCII:
Tous les points de code inférieurs à 128 sont codés comme
0xxxxxxx
.Tous les autres points de code sont codés comme
11xxxxxx 10xxxxxx ... 10xxxxxx
.Cela signifie que le codage de chaque caractère Unicode contient soit un seul
0xxxxxxx
octet, soit un seul11xxxxxx
octet et 1 à 510xxxxxx
octets.En divisant tous les octets de l'entrée par 64 , nous transformons
0xxxxxxx
en 0 ou 1 ,11xxxxxx
en 3 et10xxxxxx
en 2 .Si nous comparons le quotient avec 2 - pousser 1 pour 2 ; et 0 pour 0 , 1 et 3 - chaque caractère sera transformé en 0 , suivi de 1 à 5 1 .
Il ne reste plus qu'à diviser la chaîne résultante à des occurrences de 0 , à compter le nombre de 1 entre ces zéros et à en ajouter un au montant.
Comment ça marche
la source
PowerShell v4, 58 octets
NB
OK, cela devrait fonctionner, et fonctionne dans presque tous les cas de test, sauf pour
𩸽
ce qui est en quelque sorte compté comme3,3
sur ma machine. Ce caractère s'affiche même sous forme de 7 octets sur mon ordinateur. Je soupçonne que cela est dû à une sorte de bogue dans la version Windows ou .NET que j'exécute localement, car @Mego n'a pas ce problème . ( Edit: @cat souligne que cela est dû à la nomenclature . Merci d'avoir résolu ce mystère, @cat! )Cependant, cela ne explique toujours pas tout le problème. Je pense que je sais d’où viennent certains des problèmes. Dans .NET, toutes les chaînes sont composées d' unités de code UTF-16 (qui est le type System.Char). Avec la conversion de caractères très lâche que PowerShell utilise, il y a beaucoup de transtypage implicite et de conversion entre les types en arrière-plan. Il s'agit probablement d' un facteur contribuant au comportement que nous constatons - par exemple,
[system.text.encoding]::utf8.getchars([System.Text.UTF8Encoding]::UTF8.GetBytes('𩸽'))
renvoie deux non imprimables, plutôt qu'un seul caractère.Explication
Code très simple. Prend l'entrée
$args[0]
et la transforme explicitement en un tableau de caractères afin que nous puissions parcourir chaque composant de la chaîne|%{...}
. Chaque itération, nous utilisons l'appel .NET[System.Text.Encoding]::UTF8.GetByteCount()
(leSystem.
est implicite) pour obtenir le nombre d'octets du caractère courant$_
. Cela est placé sur le pipeline pour une sortie ultérieure. Puisqu'il s'agit d'une collection de[int]
s qui sont retournés, la conversion dans un tableau est implicite.Exécutions de test
Modifié pour ajouter Cela tient correctement compte de l'exigence d'octets nuls qui a été ajoutée au défi après la publication initiale, à condition de extraire les données d'un fichier texte et de les diriger comme suit:
la source
That character even shows as 7 bytes on my computer.
Oui, c'est à cause de Byte-Order Mark qui est ce que vous obtenez sur Windows avec UTF-8. Dites à Notepad ++ d'utiliserUTF-8 without BOM
(car vous devez toujours éviter la nomenclature , en particulier pour la compatibilité avec Unicies) et vous trouverez que le fichier a une taille de 4 octets, car la nomenclature est 3 et 4 + 3 = 7get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}
revient toujours3,3
.-Encoding
paramètre ne semble pas être pris en charge .JavaScript (ES6),
544543 octetsEdit: enregistré 2 octets avec l'aide de @ l4m2.
la source
s=>[...s].map(c=>encodeURI(c).length/3-4&3)
Rubis, 33 octets
À peine dépasse Python, yay! Essayez-le en ligne.
la source
Perl 6 ,
77 6963 octetsÉtant donné que Perl 6 utilise des chaînes NFG, je dois tirer directement les octets, ce qui contourne la fonctionnalité.
(NFG est comme NFC, sauf qu'il crée également des points de code composés synthétiques)
La sortie est séparée par des retours à la ligne.
Tester:
Explication:
Cela fonctionne parce que le premier octet d'un codet à plusieurs octets a le nombre d'octets codés à l'intérieur de celui-ci, et les autres octets du codet ont le bit le plus élevé défini, mais pas le suivant le plus élevé. Alors que les points de code à un octet n'ont pas le bit le plus élevé.
la source
read:1
et / ou à la/while$
place? Et si ça marcheif$
,?while
.\n1\n1\n
, est-ce intentionnel? Fondamentalement, cela gère-t-il les octets NUL?perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'
je reçois414
exactement ce à quoi je m'attendais. (La partie sur nuls a été ajoutée après avoir posté)Python 3, 82 octets
C'est beaucoup plus long que l'autre réponse Python et la majorité des autres réponses, mais utilise une approche impliquant des logarithmes que je n'ai pas encore vue.
Une fonction anonyme qui prend une entrée, via un argument, sous forme de chaîne et renvoie une liste.
Essayez-le sur Ideone
Comment ça marche
Cette méthode repose sur la façon dont UTF-8 code le point de code d'un caractère. Si le point de code est inférieur à 128, le caractère est codé comme en ASCII:
où
x
représente les bits du point de code. Cependant, pour les points de code supérieurs ou égaux à 128, le premier octet est rempli avec le même nombre de1
s que le nombre total d'octets et les octets suivants commencent10
. Les bits du point de code sont ensuite entrés pour donner la séquence multi-octets la plus courte possible, et tous les bits restants deviennent0
.et ainsi de suite.
On peut maintenant remarquer que pour chaque nombre d'octets
n
, la limite supérieure du nombre de bits de point de code est donnée par(-n+7)+6(n-1) = 5n+1
. Par conséquent, le pointc
de code de limite supérieure pour chacunn
est donné, en décimal, parc= 2^(5n+1)
. Réorganiser cela donnen = (log2(c)-1)/5
. Donc, pour tout point de code, le nombre d'octets peut être trouvé en évaluant l'expression ci-dessus, puis en prenant le plafond.Cependant, cela ne fonctionne pas pour les points de code de la plage
64 <= c <= 127
, car l'absence de remplissage en1
raison du codage de type ASCII pour les caractères à 1 octet signifie que la mauvaise limite supérieure est prédite etlog2
n'est pas définie pourc = 0
, ce qui se produit si un octet nul est présent dans l'entrée. Par conséquent, sic <= 127
, une valeur de1
est renvoyée pour n.C'est exactement ce que fait le code; pour chaque caractère
i
de la chaînex
, le point de code est trouvé à l'aide de laord
fonction, et le plafond de l'expression est trouvé en utilisant l'entier plutôt que la division flottante par5
puis en ajoutant1
. Étant donné que le type float de Python représente toujours des entiers carx.0
, même après une division entière, le résultat est transmis à laint
fonction pour supprimer le zéro de fin. Siord(i) <= 127
, un court-circuit logique signifie qu'il1
est renvoyé à la place. Le nombre d'octets pour chaque caractère est stocké en tant qu'élément dans une liste, et cette liste est renvoyée.la source
Java 10,
10096956761 octets-4 octets supprimant les espaces car cela est autorisé dans les commentaires
-1 octet passant
UTF-8
àutf8
-28 octets allant de Java 7 à 8 (
a->{...}
au lieu devoid c(char[]i)throws Exception{...}
)-3 octets prenant l'entrée comme String-array au lieu de character-array, et
-3 bytes passer de Java 8 à 10 (
var
au lieu deString
)Explication:
Essayez-le en ligne.
la source
Julia, 34 octets
Il s'agit d'une fonction anonyme qui accepte une chaîne et renvoie un tableau d'entiers. Pour l'appeler, affectez-le à une variable.
L'approche est assez simple: si l'entrée est vide, la sortie est vide. Sinon, nous mappons la
sizeof
fonction, qui compte le nombre d'octets dans une chaîne, à chaque sous-chaîne à un caractère.Essayez-le en ligne! (inclut tous les cas de test)
la source
s->[sizeof("$c")for c=s]
enregistre quelques octets.split("","")
revient pas[]
? (JavaScript le"".split("")
fait.)split("","")
semble donner""
(contrairement à Python qui donne une exception) mais je ne sais rien de la compatibilité de[]
et""
en julia.split("", "") == [""]
c'est-à-dire un tableau à un élément contenant une chaîne vide, mais le problème est celuisizeof("") == 0
qui, selon l'OP, n'est pas autorisé.PHP,
9257 octetsÀ bien y penser, vous pouvez le faire avec beaucoup moins de défauts:
Essayez-le en ligne, notez qu'il est légèrement plus long car il utilise stdin plutôt qu'un argument de programme.
Cette version vous oblige à ignorer les notifications envoyées à stderr mais c'est très bien .
ancienne version:
utilise une approche assez différente de l'autre réponse php. Repose sur le manque de support natif pour les chaînes multi-octets en php.
la source
<?=
Emacs Lisp,
5549 octetsCommence par disséquer la chaîne dans une liste de caractères avec
(mapcar 'string s)
. Lastring
fonction dans Emacs Lisp prend une liste de caractères et construit une chaîne à partir d'eux. En raison de la façon dont Emacs fractionne les chaînesmapcar
(c'est-à-dire en une liste d'entiers, pas de caractères ou de chaînes), cette conversion explicite est nécessaire. Mappe ensuite lastring-bytes
fonction sur cette liste de chaînes.Exemple:
Testcases:
Ancienne réponse:Non golfé:
Testcases:
la source
nil
si vous aplatissez le résultat?nil
est une liste vide (et la seule façon de dire "faux" dans Emacs). Bien qu'il n'y ait pas d'aplatissement standard dans Emacs (vous pouvez utiliser des tirets-flatten
), toute implémentation possible l'éliminerait.JavaScript (nœud), 27 octets
Cela prend l'entrée comme un tableau de caractères individuels et retourne un tableau de nombres d'octets.
Buffer
est une méthode de représentation des données binaires brutes. Buffer.byteLength (string) donne le nombre d'octets dans la chaîne. UTF-8 est le codage par défaut. Notez que seul Node.js possède des tampons, pas le navigateur JS. L'équivalent approximatif du navigateur est appelé Blob , qui se présente à 31 octets:Tester
Enregistrez ce fichier et exécutez-le via le nœud, ou essayez-le en ligne .
Cela devrait être le résultat:
la source
Bash, 74 octets
Golfé
Algorithme
hexdump chaîne d'entrée, pliez 2 caractères par ligne, coupez le premier caractère uniquement
(4 bits de poids fort d'un octet d'entrée en tant que caractère hexadécimal, un par ligne)
Supprimer les "octets de continuation" 0x80..0xBF
(ce qui reste, c'est 4 bits du premier octet de chaque caractère unicode)
mappez les premiers bits dans la longueur du caractère, réduisez la sortie et imprimez
Tester
la source
-t
option pourtr
ne m'était pas familière et est apparemment une extension GNU. Le piping vers la substitution de commande aprèsecho
peut également valoir une explication légèrement plus détaillée.PHP, 126 octets
Essayez-le en ligne!
la source
<?=($s=fgets(STDIN))?
C #,
8982 octetsUn lambda C # simple qui parcourt la chaîne et renvoie la liste séparée par des espaces.
Edit: économisé 6 octets grâce à de très bons commentaires.
la source
var J="";...
1121
et que1 2 1 2
les deux sont OK} return J;};
using System.Text
ou à peu près - les importations ne sont pas gratuites.Haskell, 85 octets
la source
map$...
Pyth, 17 octets
Essayez-le en ligne!
Utilisez le point de code des caractères avec certains arithmétiques.
la source
C, 85 octets.
Examine les 4 bits de poids fort de chaque octet pour déterminer le codage et le nombre d'octets suivants à ignorer;
la source
while *c
sorties sur une chaîne vide et le `c + = d 'saute les null au milieu d'un codet multi-octets.char*
, vraiment) en C est marquée par un octet nul. Il est impossible de distinguer les octets nuls de la fin réelle de la chaîne.Facteur,
57878280 octetsExpliqué:
Tests unitaires:
Ils passent tous, maintenant. c:
la source
Swift 2.2,
675250 octetsHorriblement moche. Il n'y a aucun moyen d'obtenir la longueur UTF-8 d'un caractère dans Swift, donc je dois parcourir la chaîne par caractère, convertir le
Character
en aString
et trouver lecount
caractère uniqueString
(hé, au moins il y a un intégré méthode pour le faire). Recherche d'optimisations, éventuellement à l'aide d'un scanner.Révision 1: 15 octets enregistrés en utilisant
count
au lieu deunderestimateCount()
.Révisions 2: enregistré 2 autres caractères en utilisant une boucle for-in au lieu d'un pour chaque fermeture.
la source
Rouille, 53 octets
Rust a des primitives, des itérateurs et des lambdas char utf-8, donc c'était simple. Code de test:
Les sorties
la source
jq, 26 caractères
(Code de 23 caractères + option de ligne de commande de 3 caractères)
Espérons que je suis en compétition. Bien qu'il ait
utf8bytelength
été ajouté 9 ++ mois avant cette question, il n'est toujours pas inclus dans la version publiée.Exemple d'exécution:
la source
C (gcc) , 53 octets
Essayez-le en ligne!
la source
SmileBASIC, 69 octets
L'entrée est un tableau d'octets.
Le nombre d'octets dans un caractère UTF-8 est égal au nombre de
1
bits de tête dans le premier octet (sauf s'il n'y a pas de1
s, auquel cas le caractère est de 1 octet). Pour trouver le nombre de 1 en tête, le programme recherche le premier0
dans la représentation binaire, puis ajoute 1 s'il s'agit de 0.la source
F #,
595466 octetsTechniquement, s est une séquence de caractères, mais il s'avère qu'il existe une conversion implicite qui permet de passer une chaîne.
Lorsque vous testez cela dans la console avec
!±≡𩸽
, il divise le kanji en deux caractères, chacun de 3 octets de long. Tous les autres cas de test fonctionnent bien.Edit: Il s'avère que les importations d'espace de noms communes ne sont pas implicites. Jusqu'à 12 autres caractères.
la source
UTF-8 without BOM
cela est faux et devrait être corrigé. 3) On dirait que F # a besoin d'instructions commelet f(x)= ...
pour finir;;
, comme SML. 4) Vous pouvez ne pas attribuer un nom à cette fonction anonyme, c'est-à-dire(s)=seq{for c in s->Encoding.UTF8.GetByteCount([|c|])}
.error FS0039: The namespace or module 'Encoding' is not defined
en essayant de faire ça. Qu'est-ce que je fais mal?System.Text
espace de noms. Je suppose que l'espace de noms s'ouvre et que le code d'entrée est inclus, provenant de la réponse C # d'AstroDan.import
,#include
,open
,load
,require
,using
,USING:
etc ici sur PPCG. La réponse C # d'AstroDan est également erronée, et je les ai informés de cela.05AB1E , 15 octets
Essayez-le en ligne.
L'en-tête
ε
est utilisé pour for-each sur tous les cas de test;Pied
ï]J]»
depagepour imprimer les listes de caractères de sortie (ï
: décimales et caractères en entiers;:]
fermez si-autre et pour-chacunJ
;: joignez les chiffres ensemble}
;: fermez l'en-têtepour chaque;»
joignez par des nouvelles lignes).Explication:
Puisque 05AB1E n'a pas de code intégré pour convertir les caractères en nombre d'octets utilisés, j'utilise
Ç
pour convertir les caractères en leurs valeurs unicode, et dans un for-each, procédez comme suit en pseudo-code:Inspiré par la réponse Python 3 de @TheBikingViking .
la source
Zsh , 41 octets
Essayez-le en ligne!
Zsh est compatible UTF-8, nous divisons donc la chaîne en caractères, puis désactivons plusieurs octets et imprimons la longueur de chaque caractère.
la source