Octets / caractère


28

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

Ciao1 1 1 1

tʃaʊ1 2 1 2

Adám1 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.


1
Si l'entrée est vide, pouvons-nous sortir 0 ou une autre valeur de falsey?
Alex A.

2
Puis-je imprimer le nombre d'octets sans séparation? La valeur la plus élevée possible est 6, elle n'est donc pas ambiguë.
Dennis

3
Faut-il prendre en charge les octets nuls? Celles-ci peuvent être une vraie douleur dans certaines langues ...
Dennis

3
Vous devez ajouter cela au message. Je ne connais pas suffisamment la plupart des langues pour savoir si cela fait une différence, mais je pense que cela invalide au moins deux des réponses.
Dennis

2
@ Adám oui ça va. En C, par exemple, les chaînes C se terminent par un octet NUL, donc vous arrêtez de lire dès que vous en trouvez un. Si vous connaissez la longueur de la chaîne, vous arrêtez de lire après autant d'octets, NUL et tout.
cat

Réponses:


10

Pyth, 9 7 octets

Merci à @Maltysen d'avoir économisé 2 octets!

mlc.Bd8

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.


1
vous pouvez enregistrer 2 octets avec fractionnement au lieu de diviser, puis supprimer le .E pyth.herokuapp.com/…
Maltysen

@Maltysen C'est intelligent, merci!
Denker

1
Réponse de même longueur qui repose sur une astuce similaire:mlhc8.B
FryAmTheEggman

@LeakyNun alors ce serait simple de donner un cas de test qui échoue, non?
Lause

Pour enregistrer un autre octet, au lieu de se diviser en morceaux de 8, prenez tous les 8: ml%8.B(maintenant dc'est implicite).
Anders Kaseorg

21

Python 3, 42 36 octets

lambda x:[len(i.encode())for i in x]

13
-1 octet: utiliser map. lambda x:map(len,map(str.encode,x))
NoOneIsHere

11

C, 68 65 octets

b;main(c){for(;~c;b=c/64^2?b?putchar(b+48)/48:1:b+1)c=getchar();}

Merci à @FryAmTheEggman pour avoir joué au golf sur 3 octets!

Testez-le sur Ideone .


11

APL, 15 caractères

≢¨'UTF-8'∘⎕ucs¨

En anglais: convertissez chaque caractère en UTF-8 (ce qui signifie: vecteur de représentation des octets) et obtenez son décompte.


Enregistrer un octet:≢¨'UTF-8'∘⎕ucs¨
Adám

En effet @ Adám ... Cheers.
lstefano

Une approche basée sur les tableaux intéressante (mais plus longue):+⌿0 7 11 16∘.≤2⍟⎕UCS
Adám

Version 16.0:0 7 11 16⍸2⍟⎕UCS
Adám

7

GolfScript, 16 octets

{64/2=}%1,/{,)}*

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 0xxxxxxxoctet, soit un seul 11xxxxxxoctet et 1 à 5 10xxxxxxoctets.

En divisant tous les octets de l'entrée par 64 , nous transformons 0xxxxxxxen 0 ou 1 , 11xxxxxxen 3 et 10xxxxxxen 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

{     }%          Map the following over all bytes in the input.
 64/                Divide the byte by 64.
    2=              Compare the quotient with 2, pushing 1 or 0.
        1,        Push range(1), i.e., [0].
          /       Split the array of Booleans around zeroes.
           {  }*  Fold; for each run of ones but the first:
            ,       Push its length.
             )      Increment.

6

PowerShell v4, 58 octets

[char[]]$args[0]|%{[Text.Encoding]::UTF8.GetByteCount($_)}

NB

OK, cela devrait fonctionner, et fonctionne dans presque tous les cas de test, sauf pour 𩸽ce qui est en quelque sorte compté comme 3,3sur 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()(le System.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

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'tʃaʊ'
1
2
1
2

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'Adám'
1
1
2
1

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'ĉaŭ'
2
1
2

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'ĉaŭ'
1
2
1
1
2

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 'チャオ'
3
3
3

PS C:\Tools\Scripts\golfing> .\bytes-per-character.ps1 '!±≡𩸽'
1
2
3
3
3

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:

PS C:\Tools\Scripts\golfing> gc .\z.txt -Encoding UTF8|%{.\bytes-per-character.ps1 $_}
2
1
1
1

z.txt


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'utiliser UTF-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 = 7
cat

@cat Ah, oui, cela a du sens. OK, ce qui explique la différence de taille de fichier. Cependant, cela ne tient toujours pas compte du comportement différent à l'intérieur du shell lui-même. Par exemple, l'enregistrer au format UTF-8 sans nomenclature, et l'exécution get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}revient toujours 3,3.
AdmBorkBork



6

JavaScript (ES6), 54 45 43 octets

s=>[...s].map(c=>encodeURI(c).length/3-8&7)

Edit: enregistré 2 octets avec l'aide de @ l4m2.


s=>[...s].map(c=>encodeURI(c).length/3-4&3)
l4m2

@ l4m2 Cela échoue pour les caractères non-BMP mais j'ai pu le réparer.
Neil


5

Perl 6 ,  77 69  63 octets

put +$0 if $_».base(2).fmt("%8d")~~/^(1)**2..*|^(" ")/ while $_=$*IN.read: 1
put +$0 if $_».fmt("%8b")~~/^(1)**2..*|^(" ")/ while $_=$*IN.read: 1

put 1+$0 if $_».fmt("%8b")~~/^1(1)+|^" "/while $_=$*IN.read: 1
put 1+$0 if $_».fmt("%0.8b")~~/^1(1)+|^0/while $_=$*IN.read: 1

É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:

for text in '!' 'Ciao' 'tʃaʊ' 'Adám' 'ĉaŭ' 'ĉaŭ' 'チャオ' '' '!±≡𩸽' '𩸽\0𩸽';
do
  echo -en $text |
  perl6 -e 'put 1+$0 if $_».fmt("%8b")~~/^1(1)+|^" "/while $_=$*IN.read: 1' |

  # combine all of the lines into a single one for display purposes
  env text=$text perl6 -e 'put qq["%*ENV<text>"], "\t\t", lines.gist'
done
"!"     (1)
"tʃaʊ"      (1 2 1 2)
"Adám"      (1 1 2 1)
"ĉaŭ"       (2 1 2)
"ĉaŭ"     (1 2 1 1 2)
"チャオ"       (3 3 3)
""      ()
"!±≡𩸽"     (1 2 3 4)
"𩸽\0𩸽"        (4 1 4)

Explication:

# turns the list in 「$0」 into a count, and adds one
# 「put」 prints that with a trailing newline
put 1+$0 

   # if the following is true
   if

       # format the input byte to base 2 and pad it out to 8 characters
       $_».fmt("%8b")

       ~~ # smart match against

       # check to see if it starts with more than one 1s, or a space
       # ( also sets 「$0」 to a list that is 1 shorter
       # than the number of bytes in this codepoint )
       / ^1 (1)+ | ^" " /

           # for every byte in STDIN
           while
               $_ = $*IN.read: 1

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é.


Vous ne pouvez pas faire read:1et / ou à la /while$place? Et si ça marche if$,?
Erik the Outgolfer

@ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ Non, car cela serait analysé comme quelque chose de différent. Je peux cependant supprimer l'espace avant while.
Brad Gilbert b2gills

Pouvez-vous expliquer les contre-mesures NFG?
JDługosz

Si j'écho un octet NUL au STDIN de ce programme, il s'imprime \n1\n1\n, est-ce intentionnel? Fondamentalement, cela gère-t-il les octets NUL?
cat

@cat Pourquoi pas? Quand je fais cela: perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'je reçois 4␤1␤4exactement ce à quoi je m'attendais. (La partie sur nuls a été ajoutée après avoir posté)
Brad Gilbert b2gills

5

Python 3, 82 octets

import math
lambda x:[ord(i)<128and 1or int((math.log2(ord(i))-1)//5+1)for i in x]

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:

0xxxxxxx

xrepré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 de 1s que le nombre total d'octets et les octets suivants commencent 10. 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 deviennent 0.

No. of bytes  Format
1             0xxxxxxx
2             110xxxxx 10xxxxxx
3             1110xxxx 10xxxxxx 10xxxxxx
4             11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
...           ...

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 point cde code de limite supérieure pour chacun nest donné, en décimal, par c= 2^(5n+1). Réorganiser cela donne n = (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 en 1raison du codage de type ASCII pour les caractères à 1 octet signifie que la mauvaise limite supérieure est prédite et log2n'est pas définie pour c = 0, ce qui se produit si un octet nul est présent dans l'entrée. Par conséquent, si c <= 127, une valeur de 1est renvoyée pour n.

C'est exactement ce que fait le code; pour chaque caractère ide la chaîne x, le point de code est trouvé à l'aide de la ordfonction, et le plafond de l'expression est trouvé en utilisant l'entier plutôt que la division flottante par 5puis en ajoutant 1. Étant donné que le type float de Python représente toujours des entiers car x.0, même après une division entière, le résultat est transmis à la intfonction pour supprimer le zéro de fin. Si ord(i) <= 127, un court-circuit logique signifie qu'il 1est 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.


5

Java 10, 100 96 95 67 61 octets

a->{for(var c:a)System.out.print(c.getBytes("utf8").length);}

-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 de void 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 ( varau lieu de String)

Explication:

Essayez-le en ligne.

a->{                      // Method with String-array parameter and no return-type
  for(var c:a)            //  Loop over the input-array
    System.out.print(     //   Print:
      c.getBytes("utf8")  //    The bytes as array in UTF-8 of the current item,
       .length);}         //    and print the amount of bytes in this array

Cela fonctionne-t-il pour des octets nuls?
cat

@cat Le cas de test pour les octets nuls a été ajouté ultérieurement. Mais oui, cela fonctionne également pour les octets nuls et j'ai ajouté le cas de test.
Kevin Cruijssen

3

Julia, 34 octets

s->s>""?map(sizeof,split(s,"")):[]

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 sizeoffonction, 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)


s->[sizeof("$c")for c=s]enregistre quelques octets.
Dennis

Impair; ne split("","")revient pas []? (JavaScript le "".split("")fait.)
Neil

@Neil split("","")semble donner ""(contrairement à Python qui donne une exception) mais je ne sais rien de la compatibilité de []et ""en julia.
cat

@Neil Non, split("", "") == [""]c'est-à-dire un tableau à un élément contenant une chaîne vide, mais le problème est celui sizeof("") == 0qui, selon l'OP, n'est pas autorisé.
Alex A.

@Dennis Cela échouera pour les chaînes non indexables. (Je ne peux pas penser à un exemple de façon désinvolte cependant.)
Alex A.

3

PHP, 92 57 octets

À bien y penser, vous pouvez le faire avec beaucoup moins de défauts:

<?php for(;$a=strlen(mb_substr($argv[1],$i++,1));)echo$a;

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.

<?php for($l=strlen($a=$argv[1]);$a=mb_substr($a,1);$l=$v)echo$l-($v=strlen($a));echo$l?:'';

Bonne réponse! Je pense que vous pouvez supprimer la balise d'ouverture entièrement, ou la changer en<?=
cat

Sans la balise, c'est un extrait de code plutôt qu'un programme, et même si cela est autorisé, je me sens vaguement sale. Avec la balise alternative, vous obtenez une erreur d'analyse (ou du moins je l'ai fait sur php 5.5, ce à quoi je suis habitué).
user55641

D'accord :) Je ne connais pas PHP (et je ne veux pas non plus, tousser ) mais je vous pointerai ici: codegolf.stackexchange.com/questions/2913
cat

3

Emacs Lisp, 55 49 octets

(lambda(s)(mapcar'string-bytes(mapcar'string s)))

Commence par disséquer la chaîne dans une liste de caractères avec (mapcar 'string s). La stringfonction 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înes mapcar(c'est-à-dire en une liste d'entiers, pas de caractères ou de chaînes), cette conversion explicite est nécessaire. Mappe ensuite la string-bytesfonction sur cette liste de chaînes.

Exemple:

(mapcar 'string "abc") ; => ("a" "b" "c")
(mapcar 'string-bytes '("a" "b" "c")) ; => (1 1 1) 

Testcases:

(mapcar
 (lambda(s)(mapcar'string-bytes(mapcar'string s)))
 '("!""Ciao""tʃaʊ""Adám""ĉaŭ""ĉaŭ""チャオ""""!±≡𩸽""\0"))
;; ((1) (1 1 1 1) (1 2 1 2) (1 1 2 1) (2 1 2) (1 2 1 1 2) (3 3 3) nil (1 2 3 4) (1))

Ancienne réponse:

(lambda(s)(mapcar(lambda(s)(string-bytes(string s)))s))

Non golfé:

 (lambda (s)
   (mapcar
    ;; we can't use string-bytes directly,
    ;; since Emacs mapcar yields a list of ints instead of characters
    ;; therefore we need a wrapper function here. 
    (lambda (s)
      (string-bytes (string s)))
    s))

Testcases:

(mapcar
 (lambda(s)(mapcar(lambda(s)(string-bytes(string s)))s))
 '("!""Ciao""tʃaʊ""Adám""ĉaŭ""ĉaŭ""チャオ""""!±≡𩸽""\0"))
;; ((1) (1 1 1 1) (1 2 1 2) (1 1 2 1) (2 1 2) (1 2 1 1 2) (3 3 3) nil (1 2 3 4) (1))


Qu'arrive-t-il nilsi vous aplatissez le résultat?
Adám

1
@ Adám nilest 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.
Lord Yuuma

3

JavaScript (nœud), 27 octets

s=>s.map(Buffer.byteLength)

Cela prend l'entrée comme un tableau de caractères individuels et retourne un tableau de nombres d'octets.

Bufferest 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:

s=>s.map(e=>new Blob([e]).size)

Tester

Enregistrez ce fichier et exécutez-le via le nœud, ou essayez-le en ligne .

var f =
  s=>s.map(Buffer.byteLength)

var tests = [
  ["!"],
  ["C","i","a","o"],
  ["t","ʃ","a","ʊ"],
  ["A","d","á","m"],
  ["ĉ","a","ŭ"],
  ["c","̂","a","u","̆"],
  ["チ","ャ","オ"],
  [],
  ["!","±","≡","𩸽"]
];

tests.forEach(test => {
  console.log(test, f(test));
});

Cela devrait être le résultat:

$ node bytes.js
[ '!' ] [ 1 ]
[ 'C', 'i', 'a', 'o' ] [ 1, 1, 1, 1 ]
[ 't', 'ʃ', 'a', 'ʊ' ] [ 1, 2, 1, 2 ]
[ 'A', 'd', 'á', 'm' ] [ 1, 1, 2, 1 ]
[ 'ĉ', 'a', 'ŭ' ] [ 2, 1, 2 ]
[ 'c', '̂', 'a', 'u', '̆' ] [ 1, 2, 1, 1, 2 ]
[ 'チ', 'ャ', 'オ' ] [ 3, 3, 3 ]
[] []
[ '!', '±', '≡', '�' ] [ 1, 2, 3, 4 ]

3

Bash, 74 octets

Golfé

xxd -p|fold -2|cut -c1|tr -d '89ab'|echo `tr -t '01234567cbef' '[1*]2234'`

Algorithme

hexdump chaîne d'entrée, pliez 2 caractères par ligne, coupez le premier caractère uniquement

echo -ne '!±≡𩸽' | xxd -p|fold -2|cut -c1

2
c
b
e
8
a
f
a
b
b

(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

tr -d '89ab'

2
c

e


f

(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

echo `tr -t '01234567cbef' '[1*]2234'`

1 2 3 4

Tester

 U() { xxd -p|fold -2|cut -c1|tr -d '89ab'|echo `tr -t '01234567cbef' '[1*]2234'`;}

 echo -ne '!' | U 
 1

 echo -ne 'Ciao' | U
 1 1 1 1

 echo -ne 'tʃaʊ' | U
 1 2 1 2

 echo -ne 'Adám' | U
 1 1 2 1

 echo -ne 'ĉaŭ' | U
 2 1 2

 echo -ne 'ĉaŭ' | U
 1 2 1 1 2

 echo -ne 'チャオ' | U
 3 3 3
 echo -ne '!±≡𩸽' | U
 1 2 3 4

 echo -ne "\x0" | U
 1

 echo -ne '' | U

+1 Belle approche. En fait, vous lisez le résultat directement à partir de l'entrée.
Adám

L' -toption pour trne m'était pas familière et est apparemment une extension GNU. Le piping vers la substitution de commande après echopeut également valoir une explication légèrement plus détaillée.
tripleee


2

C #, 89 82 octets

I=>{var J="";foreach(char c in I){J+=Encoding.UTF8.GetByteCount(c+"");}return J;};

Un 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.


à peu près sûr que vous pouvez le fairevar J="";...
chat

De plus, l'OP indique dans un commentaire que vous n'avez pas besoin de séparer l'espace de la sortie 1121et que 1 2 1 2les deux sont OK
cat

1
@cat Merci, m'a sauvé 6 octets
AstroDan

De plus, vous avez un espace supplémentaire dans} return J;};
cat

Il semble que vous en ayez besoin using System.Textou à peu près - les importations ne sont pas gratuites.
cat

2

Haskell, 85 octets

import Data.ByteString as B
import Data.ByteString.UTF8
(B.length.fromString.pure<$>)

Un peu tard, mais ce serait plus court carmap$...
H.PWiz


1

C, 85 octets.

l(unsigned char* c){while(*c){int d=(*c>>4)-11;
d=d<0?1:d+(d==1);putchar(48+d);c+=d;}}

Examine les 4 bits de poids fort de chaque octet pour déterminer le codage et le nombre d'octets suivants à ignorer;


Est-ce que cela fonctionne sur des octets nuls?
cat

Oui, les while *c sorties sur une chaîne vide et le `c + = d 'saute les null au milieu d'un codet multi-octets.
AShelly

1
C'est faux. La fin d'une chaîne ( 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.
Dennis

@Dennis Précisément parce qu'il n'y a pas de différence :)
cat

1
L'OP a déclaré dans un commentaire (et c'est maintenant dans le message) que vous pouvez demander la longueur de la chaîne en octets comme argument, alors faites-le et cela sera à nouveau valide
cat

1

Facteur, 57 87 82 80 octets

[ [ dup zero? [ drop "1"] [ >bin length 4 /i 10 >base ] if ] { } map-as ""join ]

Expliqué:

USING: kernel math math.parser sequences ;
IN: byte-counts

: string>byte-counts ( str -- counts )
  [                  ! new quotation: takes a char as a fixnum
    dup zero?        ! true if this is a NUL byte
    [ drop "1" ]     ! NUL bytes have length 1
    [ >bin           ! else, convert to binary string
      length         ! length of binary string
      4              ! the constant 4
      /i             ! integer division
      number>string  ! 4 -> "4"
    ] if             ! conditionally execute one of the previous quotations
  ]                  ! end
  { } map-as         ! map and clone-like an { } array
  "" join ;          ! join array of 1strings on empty string

Tests unitaires:

USING: tools.test byte-counts ;
IN: byte-counts.tests

{ "1" } [ "!" string>byte-counts ] unit-test
{ "1111" } [ "Ciao" string>byte-counts ] unit-test
{ "1212"} [ "tʃaʊ" string>byte-counts ] unit-test
{ "1121" } [ "Adám" string>byte-counts ] unit-test
{ "212" } [ "ĉaŭ" string>byte-counts ] unit-test
{ "12112" } [ "ĉaŭ" string>byte-counts ] unit-test
{ "333" } [ "チャオ" string>byte-counts ] unit-test
{ "" } [ "" string>byte-counts ] unit-test
{ "1234" } [ "!±≡𩸽" string>byte-counts ] unit-test
{ "1" } [ "\0" string>byte-counts ] unit-test

Ils passent tous, maintenant. c:


1

Swift 2.2, 67 52 50 octets

for c in i.characters{print(String(c).utf8.count)}

Horriblement 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 Characteren a Stringet trouver le countcaractè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 countau lieu de underestimateCount().

Révisions 2: enregistré 2 autres caractères en utilisant une boucle for-in au lieu d'un pour chaque fermeture.


1

Rouille, 53 octets

|s:&str|for c in s.chars(){print!("{}",c.len_utf8())}

Rust a des primitives, des itérateurs et des lambdas char utf-8, donc c'était simple. Code de test:

fn main() {
    let s = "Löwe 老虎 Léopard💖💖💖💖";
    let f =|s:&str|for c in s.chars(){print!("{}",c.len_utf8())};
    f(s);
}

Les sorties

1211133112111114444 

1

jq, 26 caractères

(Code de 23 caractères + option de ligne de commande de 3 caractères)

(./"")[]|utf8bytelength

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:

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< 'tʃaʊ'
1
2
1
2

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< 'ĉaŭ '
1
2
1
1
2
1

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< 'チャオ'
3
3
3

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< ''

bash-4.3$ ./jq -R '(./"")[]|utf8bytelength' <<< '!±≡𩸽'
1
2
3
4


1

SmileBASIC, 69 octets

DEF C B
WHILE I<LEN(B)Q=INSTR(BIN$(B[I],8),"0")I=I+Q+!Q?Q+!Q
WEND
END

L'entrée est un tableau d'octets.

Le nombre d'octets dans un caractère UTF-8 est égal au nombre de 1bits de tête dans le premier octet (sauf s'il n'y a pas de 1s, auquel cas le caractère est de 1 octet). Pour trouver le nombre de 1 en tête, le programme recherche le premier 0dans la représentation binaire, puis ajoute 1 s'il s'agit de 0.

0xxxxxxx - no leading ones, 1 byte
110xxxxx 10xxxxxx - 2 leading ones, 2 bytes
1110xxxx 10xxxxxx 10xxxxxx - 3 leading ones, 3 bytes
etc.

1

F #, 59 54 66 octets

(s)=seq{for c in s->System.Text.Encoding.UTF8.GetByteCount([|c|])}

Techniquement, 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.


1) La réponse PowerShell de Timmy D a le même problème de 6 octets par kanji. Je l'attribuerais à Windows étant stupide et inutile chez Unicode. 2) Si vous obtenez 6 octets pour le kanji lors de la lecture à partir d'un fichier entré, UTF-8 without BOMcela est faux et devrait être corrigé. 3) On dirait que F # a besoin d'instructions comme let 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|])}.
cat

Aussi, j'obtiens error FS0039: The namespace or module 'Encoding' is not defineden essayant de faire ça. Qu'est-ce que je fais mal?
cat

Aussi, bienvenue dans Programming Puzzles et Code Golf, c'est une bonne première réponse! : D
cat

@cat Vous devez ouvrir l' System.Textespace 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.
interface scellée

Vous devez compter les octets de tout 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.
cat

1

05AB1E , 15 octets

ÇεDžy‹i1ë.²<5÷>

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:

Ç                   # Convert each character to its unicode value
 εD                 # Foreach over this list
      i             #  If the current item
     ‹              #  is smaller than
   žy               #  128
       1            #   Use 1
        ë           #  Else
         .²         #   Use log_2
           <        #   minus 1
            5÷      #   integer-divided by 5
              >     #   plus 1

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:

if(unicodeValue < 128)
  return 1
else
  return log_2(unicodeValue-1)//5+1    # (where // is integer-division)

Inspiré par la réponse Python 3 de @TheBikingViking .


0

Zsh , 41 octets

for c (${(s::)1})set +o multibyte&&<<<$#c

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.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.