Bytes / Character


28

Aufgabe

Wenn eine UTF-8-Zeichenfolge (mit allen Mitteln) angegeben wird, antworten Sie (mit allen Mitteln) auf eine äquivalente Liste, wobei jedes Element die Anzahl der Bytes ist, die zum Codieren des entsprechenden Eingabezeichens verwendet werden.

Beispiele

!1

Ciao1 1 1 1

tʃaʊ1 2 1 2

Adám1 1 2 1

ĉaŭ2 1 2(einzelne Zeichen)

ĉaŭ1 2 1 1 2(verwendet kombinierte Overlays)

チャオ3 3 3

(leere Eingabe) → (leere Ausgabe)

!±≡𩸽1 2 3 4

(ein Null-Byte) → 1

Null Bytes

Wenn die einzige Möglichkeit, Eingaben über null Bytes hinaus zu lesen, darin besteht, die Gesamtanzahl der Bytes zu kennen, können Sie die Anzahl der Bytes auf beliebige Weise ermitteln (auch durch Benutzereingaben).

Wenn Ihre Sprache überhaupt keine Null-Bytes verarbeiten kann, können Sie davon ausgehen, dass die Eingabe keine Nullen enthält.


1
Wenn die Eingabe leer ist, können wir 0 oder einen anderen Falsey-Wert ausgeben?
Alex A.

2
Kann ich die Byteanzahl ohne Trennung drucken? Der höchstmögliche Wert ist 6, es ist also eindeutig.
Dennis

3
Müssen wir null Bytes unterstützen? Das kann in manchen Sprachen ein echtes Problem sein ...
Dennis

3
Sie sollten das dem Beitrag hinzufügen. Ich kenne die meisten Sprachen nicht gut genug, um zu sagen, ob es einen Unterschied macht, aber ich denke, es macht mindestens zwei der Antworten ungültig.
Dennis

2
@Adám ja das wird es. In C beispielsweise enden C-Zeichenfolgen mit einem NUL-Byte, sodass Sie aufhören zu lesen, sobald Sie eines finden. Wenn Sie die Länge der Zeichenfolge kennen, hören Sie nach so vielen Bytes, NUL und allem auf zu lesen.
Katze

Antworten:


10

Pyth, 9 7 Bytes

Vielen Dank an @Maltysen für das Speichern von 2 Bytes!

mlc.Bd8

Testsuite

Wandelt jedes Zeichen der Eingabe in seine Binärdarstellung um und teilt diese dann in Abschnitte der Länge 8 auf. Die Anzahl dieser Abschnitte gibt dann die Anzahl der Bytes an, die zum Codieren dieses Zeichens erforderlich sind.


1
Sie können 2 Bytes sparen, indem .E Sie
aufteilen

@Maltysen Das ist klug, danke!
Denker

1
Antwort gleicher Länge, die auf einem ähnlichen Trick beruht:mlhc8.B
FryAmTheEggman

@LeakyNun dann wäre es einfach, einen Testfall zu geben, der fehlschlägt, nicht wahr?
Pause

Um ein weiteres Byte zu speichern, anstatt es in 8er-Blöcke aufzuteilen, nehmen Sie jedes achte: ml%8.B(jetzt dist das implizit).
Anders Kaseorg

21

Python 3, 42 36 Bytes

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

13
-1 Byte: verwenden map. lambda x:map(len,map(str.encode,x))
NoOneIsHere

11

C 68 65 Bytes

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

Vielen Dank an @FryAmTheEggman für das Abschlagen von 3 Bytes!

Teste es auf Ideone .


11

APL, 15 Zeichen

≢¨'UTF-8'∘⎕ucs¨

In englischer Sprache: Konvertieren Sie jedes Zeichen in UTF-8 (was bedeutet: Vektor der Bytedarstellung) und erhalten Sie seine Abrechnung.


Speichern Sie ein Byte:≢¨'UTF-8'∘⎕ucs¨
Adám

In der Tat @ Adám ... Prost.
Lstefano

Ein interessanter (aber längerer) Array-basierter Ansatz:+⌿0 7 11 16∘.≤2⍟⎕UCS
Adám

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

7

GolfScript, 16 Bytes

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

Probieren Sie es online!

Hintergrund

GolfScript hat keine Ahnung, was Unicode ist. Alle Zeichenfolgen (Eingabe, Ausgabe, intern) bestehen aus Bytes. Das kann zwar ziemlich ärgerlich sein, ist aber perfekt für diese Herausforderung.

UTF-8 codiert ASCII- und Nicht-ASCII-Zeichen unterschiedlich:

  • Alle Codepunkte unter 128 werden als codiert 0xxxxxxx.

  • Alle anderen Codepunkte werden als codiert 11xxxxxx 10xxxxxx ... 10xxxxxx.

Dies bedeutet, dass die Codierung jedes Unicode-Zeichens entweder ein einzelnes 0xxxxxxxByte oder ein einzelnes 11xxxxxxByte und 1 bis 5 10xxxxxxBytes enthält.

Indem wir alle Bytes der Eingabe durch 64 teilen , werden wir 0xxxxxxxzu 0 oder 1 , 11xxxxxxzu 3 und 10xxxxxxzu 2 .

Wenn wir den Quotienten mit 2 vergleichen, drücken wir 1 für 2 ; und 0 für 0 , 1 und 3 - jedes Zeichen wird zu einer 0 , gefolgt von 1 bis 5 1 .

Alles , was übrig bleibt, ist die resultierende Zeichenfolge an Vorkommen von aufzuspalten 0 , zählen die Anzahl der 1 ‚s zwischen den Nullen und fügen Sie ein in die Menge.

Wie es funktioniert

{     }%          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 Byte

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

NB

OK, das sollte funktionieren und funktioniert in fast allen Testfällen, mit Ausnahme 𩸽derer, die irgendwie als 3,3auf meinem Computer gezählt werden. Dieses Zeichen wird auf meinem Computer sogar als 7 Byte angezeigt. Ich vermute, dass dies an einem Fehler in der Windows- oder .NET-Version liegt, die ich lokal ausführe, da @Mego dieses Problem nicht hat . ( Edit: @cat weist darauf hin, dass dies an der Stückliste liegt . Vielen Dank für die Lösung dieses Rätsels, @cat! )

Dies erklärt jedoch immer noch nicht das ganze Problem. Ich glaube jedoch zu wissen, woher einige der Probleme kommen. In .NET bestehen alle Zeichenfolgen aus UTF-16-Codeeinheiten (dies ist der Typ System.Char). Mit der sehr losen Typumwandlung, die von PowerShell verwendet wird, wird im Hintergrund viel implizites Casting und Konvertieren zwischen Typen durchgeführt. Wahrscheinlich ist dies ein Faktor, der zum Verhalten beiträgt, das wir beobachten. Beispielsweise werden [system.text.encoding]::utf8.getchars([System.Text.UTF8Encoding]::UTF8.GetBytes('𩸽'))zwei nicht druckbare Zeichen anstelle eines einzelnen Zeichens zurückgegeben.


Erläuterung

Sehr einfacher Code. Nimmt die Eingabe $args[0]und wandelt sie explizit in ein Zeichen-Array um, damit wir jede Komponente des Strings durchlaufen können |%{...}. Bei jeder Iteration verwenden wir den .NET-Aufruf [System.Text.Encoding]::UTF8.GetByteCount()(der System.impliziert ist), um die Byteanzahl des aktuellen Zeichens abzurufen $_. Das ist in der Pipeline für die spätere Ausgabe platziert. Da es sich um eine Sammlung von [int]s handelt, die zurückgegeben werden, ist das Umwandeln in ein Array implizit.

Testläufe

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

Zum Hinzufügen bearbeitet Dies berücksichtigt die Null-Byte-Anforderung, die der Herausforderung nach dem ursprünglichen Posten hinzugefügt wurde, vorausgesetzt, Sie ziehen die Daten aus einer Textdatei und leiten sie wie folgt weiter:

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.Ja, das liegt an der Byte-Order Mark, die Sie unter Windows mit UTF-8 erhalten. Weisen Sie Notepad ++ an , die Stückliste zu verwenden UTF-8 without BOM(da Sie die Stückliste insbesondere aus Gründen der Kompatibilität mit Unicies immer vermeiden sollten), und Sie werden feststellen, dass die Datei eine Größe von 4 Bytes hat, da die Stückliste 3 und 4 + 3 = 7 ist
cat

@cat Ah ja, das macht Sinn. OK, so dass der Unterschied in der Dateigröße berücksichtigt wird. Dies erklärt jedoch immer noch nicht das unterschiedliche Verhalten innerhalb der Shell. Wenn Sie es beispielsweise als UTF-8 ohne Stückliste speichern und dann ausführen, wird es get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}weiterhin ausgeführt 3,3.
AdmBorkBork



6

JavaScript (ES6), 54 45 43 Byte

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

Bearbeiten: 2 Bytes mit Hilfe von @ l4m2 gespeichert.


s=>[...s].map(c=>encodeURI(c).length/3-4&3)
14 m²,

@ l4m2 Das schlägt bei Nicht-BMP-Zeichen fehl, aber ich konnte es beheben.
Neil


5

Perl 6 ,  77 69  63 Bytes

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

Da Perl 6 NFG-Strings verwendet, muss ich die Bytes direkt einlesen, was die Funktion umgeht.
(NFG ähnelt NFC, es werden jedoch auch synthetisch zusammengesetzte Codepunkte erstellt.)

Die Ausgabe wird durch Zeilenumbrüche getrennt.

Prüfung:

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)

Erläuterung:

# 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

Dies funktioniert, weil das erste Byte in einem Mehrbyte-Codepunkt die Anzahl der darin codierten Bytes aufweist und die anderen Bytes im Codepunkt das höchste gesetzte Bit haben, jedoch nicht das nächsthöhere. Während die Einzelbyte-Codepunkte nicht das höchste gesetzte Bit haben.


Kann nicht read:1und / oder /while$stattdessen? Und wenn das klappt if$,?
Erik der Outgolfer

@EʀɪᴋᴛʜᴇGᴏʟғᴇʀ Nein, weil das als etwas anderes analysiert würde. Ich kann das Leerzeichen aber vorher entfernen while.
Brad Gilbert b2gills

Können Sie die Gegenmaßnahmen der NFG erklären?
JDługosz

Wenn ich ein NUL-Byte an die STDIN dieses Programms zurücksende, wird es gedruckt. Ist \n1\n1\ndas beabsichtigt? Grundsätzlich behandelt dies NUL-Bytes?
Katze

@cat Warum würde es nicht? Wenn ich das tue, perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'bekomme ich 4␤1␤4genau das, was ich erwarten würde. (Der Teil über Nuls wurde hinzugefügt, nachdem ich allerdings gepostet habe)
Brad Gilbert b2gills

5

Python 3, 82 Bytes

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

Dies ist viel länger als die andere Python-Antwort und die meisten anderen Antworten, verwendet jedoch einen Ansatz mit Logarithmen, den ich noch nicht gesehen habe.

Eine anonyme Funktion, die Eingaben über Argumente als Zeichenfolge akzeptiert und eine Liste zurückgibt.

Probieren Sie es auf Ideone

Wie es funktioniert

Diese Methode basiert auf der Art und Weise, wie UTF-8 den Codepunkt eines Zeichens codiert. Wenn der Codepunkt kleiner als 128 ist, wird das Zeichen wie in ASCII codiert:

0xxxxxxx

wo xrepräsentiert die Bits des Codepunktes. Bei Codepunkten größer oder gleich 128 wird das erste Byte jedoch mit der gleichen Anzahl von 1s wie die Gesamtanzahl von Bytes aufgefüllt , und nachfolgende Bytes beginnen 10. Die Bits des Codepunkts werden dann eingegeben, um die kürzestmögliche Multibyte-Sequenz zu ergeben, und alle verbleibenden Bits werden 0.

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

und so weiter.

Es kann nun bemerkt werden, dass für jede Anzahl von Bytes ndie Obergrenze für die Anzahl von Codepunktbits durch gegeben ist (-n+7)+6(n-1) = 5n+1. Daher wird der obere Grenzcodepunkt cfür jeden nin Dezimalzahl angegeben durch c= 2^(5n+1). Neuordnung gibt dies n = (log2(c)-1)/5. Für jeden Codepunkt kann die Anzahl der Bytes ermittelt werden, indem der obige Ausdruck ausgewertet und dann die Obergrenze ermittelt wird.

Dies funktioniert jedoch nicht für Codepunkte im Bereich 64 <= c <= 127, da das Fehlen einer Auffüllung 1aufgrund der ASCII-ähnlichen Codierung für 1-Byte-Zeichen bedeutet, dass die falsche Obergrenze vorhergesagt wird und log2für undefiniert ist c = 0, was bei einem Null-Byte der Fall ist ist in der Eingabe vorhanden. Wenn also c <= 127ein Wert von 1für n zurückgegeben wird.

Genau das macht der Code. Für jedes Zeichen iin der Zeichenfolge xwird der Codepunkt mithilfe der ordFunktion ermittelt, und die Obergrenze des Ausdrucks wird mithilfe einer Ganzzahl und nicht durch eine Gleitkommadivision dividiert 5und anschließend addiert 1. Da der Float-Typ von Python immer x.0Ganzzahlen darstellt, wird das Ergebnis auch nach der Ganzzahldivision an die intFunktion übergeben, um die nachstehende Null zu entfernen. Wenn ord(i) <= 127, bedeutet ein logischer Kurzschluss, dass er 1stattdessen zurückgegeben wird. Die Anzahl der Bytes für jedes Zeichen wird als Element in einer Liste gespeichert und diese Liste wird zurückgegeben.


5

Java 10, 100 96 95 67 61 Bytes

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

-4 Bytes, die Leerzeichen entfernen, da dies in den Kommentaren zulässig ist
-1 Bytes, die UTF-8in utf8
-28 Bytes geändert werden und von Java 7 auf 8 ( a->{...}anstelle von void c(char[]i)throws Exception{...})
-3 Bytes gehen, wobei die Eingabe als String-Array anstelle von Zeichenarray und
-3 Bytes verwendet wird von Java 8 auf 10 ( varstatt String)

Erläuterung:

Probieren Sie es online aus.

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

Funktioniert es für null Bytes?
Katze

@cat Der Testfall für Null-Bytes wurde später hinzugefügt. Aber ja, es funktioniert auch für Null-Bytes und ich habe den Testfall hinzugefügt.
Kevin Cruijssen

3

Julia, 34 Bytes

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

Dies ist eine anonyme Funktion, die eine Zeichenfolge akzeptiert und ein ganzzahliges Array zurückgibt. Um es aufzurufen, weisen Sie es einer Variablen zu.

Der Ansatz ist ganz einfach: Wenn die Eingabe leer ist, ist die Ausgabe leer. Andernfalls ordnen wir die sizeofFunktion, die die Anzahl der Bytes in einer Zeichenfolge zählt, jeder Teilzeichenfolge mit einem Zeichen zu.

Probieren Sie es online! (beinhaltet alle Testfälle)


s->[sizeof("$c")for c=s]spart ein paar Bytes.
Dennis

Ungerade; kommt split("","")nicht zurück []? (JavaScript "".split("")tut es.)
Neil

@Neil split("","")scheint zu geben ""(im Gegensatz zu Python, das eine Ausnahme gibt), aber ich weiß nichts über die Kompatibilität von []und ""in Julia.
Katze

@Neil Nein, split("", "") == [""]dh ein Array mit einem Element, das eine leere Zeichenfolge enthält, aber das Problem ist das sizeof("") == 0, was laut OP nicht zulässig ist.
Alex A.

@ Tennis Das wird für nicht indizierbare Zeichenfolgen fehlschlagen. (Ich kann mir allerdings kein Beispiel vorstellen.)
Alex A.

3

PHP, 92 57 Bytes

Auf den zweiten Blick können Sie dies mit weniger Aufwand tun:

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

Probieren Sie es online aus. Beachten Sie, dass dies etwas länger dauert, da stdin anstelle eines Programmarguments verwendet wird.
Bei dieser Version müssen Sie an stderr gesendete Benachrichtigungen ignorieren, aber das ist in Ordnung .

alte version:
Verwendet einen etwas anderen Ansatz als die andere PHP-Antwort. Beruht auf der mangelnden nativen Unterstützung von Multibyte-Strings in PHP.

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

Gute Antwort! Ich glaube , Sie das Starttag fallen kann ganz oder ändern Sie ihn auf<?=
Katze

Ohne das Tag ist es eher ein Code-Snippet als ein Programm, und selbst wenn das erlaubt ist, fühle ich mich irgendwie dreckig. Mit dem alternativen Tag bekommst du einen Parser-Fehler (oder zumindest habe ich das auf PHP 5.5 gemacht, was ich gewohnt bin).
User55641

Okay :) Ich kenne PHP nicht (und ich möchte auch nicht husten ), aber ich zeige es
cat

3

Emacs Lisp, 55 49 Bytes

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

Zerlegt zuerst die Zeichenfolge in eine Liste von Zeichen mit (mapcar 'string s). Die stringFunktion in Emacs Lisp erstellt aus einer Liste von Zeichen eine Zeichenfolge. Aufgrund der Art und Weise, wie Emacs Strings mit mapcar(dh in eine Liste von Ganzzahlen, nicht Zeichen oder Strings) aufteilt, ist diese explizite Konvertierung erforderlich. Ordnet die string-bytesFunktion dann dieser Liste von Zeichenfolgen zu.

Beispiel:

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

Testfälle:

(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))

Alte Antwort:

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

Ungolfed:

 (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))

Testfälle:

(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))


Was passiert mit dem, nilwenn Sie das Ergebnis verflachen?
Adám,

1
@Adam nilist eine leere Liste (und die einzige Möglichkeit, in Emacs "falsch" zu sagen). Obwohl es in Emacs keine standardmäßige Abflachung gibt (Sie können dash's verwenden -flatten), würde jede mögliche Implementierung diese beseitigen.
Lord Yuuma

3

JavaScript (Node), 27 Byte

s=>s.map(Buffer.byteLength)

Dies nimmt Eingaben als Array einzelner Zeichen und gibt ein Array von Byte-Zählern zurück.

Bufferist eine Methode zur Darstellung von binären Rohdaten. Buffer.byteLength (Zeichenfolge) gibt die Anzahl der Bytes in der Zeichenfolge an. UTF-8 ist die Standardkodierung. Beachten Sie, dass nur Node.js Puffer enthält, nicht Browser-JS. Das grobe Browser-Äquivalent heißt Blob und umfasst 31 Byte:

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

Prüfung

Speichern Sie diese Datei, und führen Sie sie über den Knoten aus, oder versuchen Sie es online .

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));
});

Dies sollte das Ergebnis sein:

$ 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 Bytes

Golf gespielt

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

Algorithmus

hexdump input string, falten Sie 2 Zeichen pro Zeile, schneiden Sie nur das erste Zeichen

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

2
c
b
e
8
a
f
a
b
b

(4 höherwertige Bits eines jeden Eingangsbytes als Hexadezimalzeichen, eines pro Zeile)

Entfernen Sie "Fortsetzungsbytes" 0x80..0xBF

tr -d '89ab'

2
c

e


f

(Was übrig bleibt, sind 4 Bits des ersten Bytes eines jeden Unicode-Zeichens.)

Ordne die ersten Bits der Zeichenlänge zu, reduziere die Ausgabe und drucke

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

1 2 3 4

Prüfung

 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 Schöner Ansatz. Sie lesen das Ergebnis tatsächlich direkt von der Eingabe ab.
Adám

Die -tOption zu trwar mir unbekannt und ist anscheinend eine GNU-Erweiterung. Das Weiterleiten an die Befehlsersetzung nach echokönnte auch eine etwas detailliertere Erklärung wert sein.
Tripleee


2

C # 89 82 Bytes

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

Ein einfaches C # -Lambda, das die Zeichenfolge durchläuft und die durch Leerzeichen getrennte Liste zurückgibt.

Bearbeiten: 6 Bytes dank einiger sehr netter Kommentare gespeichert.


ziemlich sicher, dass Sie tun könnenvar J="";...
Katze

Außerdem gibt das OP in einem Kommentar an, dass Sie die Ausgabe nicht durch Leerzeichen trennen müssen, 1121und 1 2 1 2beide in Ordnung sind
cat

1
@cat Danke, hat mich gerettet 6 Bytes
AstroDan

Außerdem haben Sie einen zusätzlichen Platz in} return J;};
cat

Scheint, als müssten Sie using System.Textoder so - Importe sind nicht kostenlos.
Katze

2

Haskell, 85 Bytes

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

Ein bisschen spät, aber das wäre kürzer alsmap$...
H.PWiz


1

C 85 Bytes.

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

Untersucht die hohen 4 Bits jedes Bytes, um die Codierung und die Anzahl der nachfolgenden zu überspringenden Bytes zu bestimmen.


Funktioniert das mit null Bytes?
Katze

Ja, die while *c Exits in einer leeren Zeichenfolge, und das `c + = d 'überspringt Nullen in der Mitte eines Mehrbyte-Codepunkts.
AShelly

1
Das ist falsch Das Ende eines Strings ( char*wirklich) in C wird mit einem Null-Byte markiert. Es ist unmöglich, null Bytes vom tatsächlichen Ende der Zeichenfolge zu unterscheiden.
Dennis

@ Tennis Genau, weil es keinen Unterschied gibt :)
Katze

1
Das OP hat in einem Kommentar (und jetzt im Beitrag) angegeben, dass Sie die Länge des Strings in Bytes als Argument anfordern können. Tun Sie dies, und dies wird wieder gültig sein
cat

1

Faktor 57 87 82 80 Bytes

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

Erklärt:

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

Unit-Tests:

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

Sie gehen jetzt alle vorbei. c:


1

Swift 2.2, 67 52 50 Bytes

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

Schrecklich hässlich. In Swift gibt es keine Möglichkeit, die UTF-8-Länge eines Zeichens zu ermitteln. Daher muss ich die Zeichenfolge nach Zeichen durchlaufen, das Characterin ein umwandeln Stringund das counteines einzelnen Zeichens suchen String(hey, es ist zumindest ein integriertes Element vorhanden) Methode, um das zu tun). Suchen Sie nach Optimierungen, möglicherweise mit einem Scanner.

Revision 1: 15 Bytes mit countanstelle von gespeichert underestimateCount().

Revision 2: Speichert weitere 2 Zeichen, indem für jeden Abschluss eine for-in-Schleife anstelle von a verwendet wird.


1

Rust, 53 Bytes

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

Rust hat utf-8-Zeichenprimitive, Iteratoren und Lambdas, das war also unkompliziert. Testcode:

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

Ausgänge

1211133112111114444 

1

jq, 26 Zeichen

(23 Zeichen Code + 3 Zeichen Befehlszeilenoption)

(./"")[]|utf8bytelength

Hoffentlich im Wettbewerb. Obwohl utf8bytelengthes 9 ++ Monate vor dieser Frage hinzugefügt wurde , ist es immer noch nicht in der veröffentlichten Version enthalten.

Probelauf:

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 Bytes

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

Die Eingabe ist ein Array von Bytes.

Die Anzahl der Bytes in einem UTF-8-Zeichen entspricht der Anzahl der führenden 1Bits im ersten Byte (es sei denn, es gibt keine 1s, in diesem Fall ist das Zeichen 1 Byte). Um die Anzahl der führenden Einsen zu ermitteln, sucht das Programm die erste 0in der Binärdarstellung und addiert 1, wenn dies 0 war.

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 Bytes

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

Technisch gesehen ist s eine Zeichenfolge, aber es stellt sich heraus, dass es eine implizite Konvertierung gibt, mit der ein String übergeben werden kann.

Wenn Sie dies in der Konsole mit testen !±≡𩸽, wird das Kanji in zwei Zeichen mit einer Länge von jeweils 3 Byte aufgeteilt. Alle anderen Testfälle funktionieren einwandfrei.

Bearbeiten: Es stellt sich heraus, dass allgemeine Namespace-Importe nicht implizit sind. Noch 12 Zeichen.


1) Die Powershell-Antwort von Timmy D weist das gleiche 6-Byte-pro-Kanji-Problem auf. Ich würde es darauf zurückführen, dass Windows bei Unicode dumm und nutzlos ist. 2) Wenn Sie 6 Bytes für das Kanji erhalten, wenn Sie aus einer Datei lesen, die mit einem Enocode versehen UTF-8 without BOMist, ist dies falsch und sollte behoben werden. 3) Wie es scheint, braucht F # Aussagen , die wie SML let f(x)= ...enden ;;. 4) Sie können aufhören, dieser anonymen Funktion einen Namen zuzuweisen, d (s)=seq{for c in s->Encoding.UTF8.GetByteCount([|c|])}. H.
Katze

Auch bekomme ich error FS0039: The namespace or module 'Encoding' is not definedbeim Versuch, dies auszuführen. Was mache ich falsch?
Katze

Willkommen auch bei Programming Puzzles und Code Golf, dies ist eine schöne erste Antwort! : D
cat

@cat Sie müssen den System.TextNamespace öffnen . Ich gehe davon aus, dass der Namespace geöffnet wird und der Eintragscode aus AstroDans C # -Antwort enthalten ist.
Sealed Interface

Sie müssen die Bytes jeder zählen import, #include, open, load, require, using, USING:etc hier auf PPCG. AstroDans C # -Antwort ist ebenfalls falsch, und ich habe sie darüber informiert.
Katze

1

05AB1E , 15 Bytes

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

Probieren Sie es online aus.
Die Kopfzeileεwird verwendet, um alle Testfälle einzeln zu bearbeiten.
Fußzeileï]J]»zum hübschen Ausdrucken der ausgegebenen Zeichenlisten (ï: Dezimalstellen und Zeichen in Ganzzahlen;:]Schließen von if-else und for-each;:Verbinden vonJZiffern};: Schließen des Headers foreach;:»Verbinden durch neue Zeilen).

Erläuterung:

Ç                   # 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

Da 05AB1E keine eingebauten Funktionen zum Konvertieren von Zeichen in die Anzahl der verwendeten Bytes hat, Çkonvertiere ich die Zeichen in ihre Unicode-Werte. In einem For- Each-Verfahren wird im Pseudocode Folgendes ausgeführt:

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

Inspiriert von @TheBikingVikings Python 3 Antwort .


0

Zsh , 41 Bytes

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

Probieren Sie es online!

Zsh ist UTF-8-fähig, daher teilen wir die Zeichenfolge in Zeichen auf, deaktivieren Multibyte und drucken die Länge der einzelnen Zeichen.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.