Б / символов


28

задача

Учитывая, что строка UTF-8 (любыми средствами) отвечает (любыми средствами) эквивалентному списку, где каждый элемент - это число байтов, используемых для кодирования соответствующего входного символа.

Примеры

!1

Ciao1 1 1 1

tʃaʊ1 2 1 2

Adám1 1 2 1

ĉaŭ2 1 2(одиночные символы)

ĉaŭ1 2 1 1 2(использует комбинированные наложения)

チャオ3 3 3

(пустой ввод) → (пустой вывод)

!±≡𩸽1 2 3 4

(нулевой байт) → 1

Нулевые байты

Если единственный способ сохранить входные данные после нулевых байтов - узнать общее количество байтов, вы можете получить количество байтов любым способом (даже пользовательским вводом).

Если ваш язык вообще не может обрабатывать нулевые байты, вы можете предположить, что входные данные не содержат нулевых значений.


1
Если вход пуст, можем ли мы вывести 0 или другое значение Фалси?
Алекс А.

2
Могу ли я напечатать количество байтов без разделения? Максимально возможное значение - 6, поэтому оно однозначно.
Деннис

3
Должны ли мы поддерживать нулевые байты? Это может быть настоящей болью в некоторых языках ...
Деннис

3
Вы должны добавить это к сообщению. Я не знаю большинство языков достаточно хорошо, чтобы сказать, если это имеет значение, но я думаю, что это делает недействительными по крайней мере два из ответов.
Деннис

2
@ Adám да, будет. Например, в C строки C заканчиваются байтом NUL, поэтому вы прекращаете чтение, как только найдете его. Если вы знаете длину строки, вы перестаете читать после этого много байтов, NUL и все.
кошка

Ответы:


10

Пиф, 9 7 байт

Спасибо @Maltysen за сохранение 2 байта!

mlc.Bd8

Тестирование

Преобразует каждый символ входных данных в его двоичное представление, а затем разбивает его на куски длиной 8. Затем количество этих кусочков - это количество байтов, необходимое для кодирования этого символа.


1
вы можете сэкономить 2 байта с разделением вместо разделения, а затем удалив .E pyth.herokuapp.com/…
Maltysen

@Maltysen Это умно, спасибо!
Денкер

1
Тот же самый ответ, который опирается на аналогичный трюк:mlhc8.B
FryAmTheEggman

@LeakyNun, тогда было бы просто дать контрольный пример, который не прошел, не так ли?
Lause

Чтобы сохранить еще один байт, вместо разбиения на куски по 8, возьмите каждый 8-й: ml%8.B(теперь dэто неявно).
Андерс Касеорг


11

C 68 65 байт

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

Спасибо @FryAmTheEggman за 3 байта!

Проверьте это на Ideone .


11

APL, 15 символов

≢¨'UTF-8'∘⎕ucs¨

На английском языке: преобразовать каждый символ в UTF-8 (что означает: вектор представления байтов) и получить его счет.


Сохраните байт:≢¨'UTF-8'∘⎕ucs¨
Адам

Действительно @ Adám ... Ура.
Истефано

Интересный (но более длинный) подход, основанный на +⌿0 7 11 16∘.≤2⍟⎕UCS
массивах

Версия 16.0:0 7 11 16⍸2⍟⎕UCS
Адам

7

GolfScript, 16 байт

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

Попробуйте онлайн!

Задний план

GolfScript не знает, что такое Unicode; все строки (входные, выходные, внутренние) состоят из байтов. Хотя это может быть довольно раздражающим, но оно идеально подходит для этой задачи.

UTF-8 по-разному кодирует символы ASCII и не-ASCII:

  • Все кодовые точки ниже 128 кодируются как 0xxxxxxx.

  • Все остальные кодовые точки кодируются как 11xxxxxx 10xxxxxx ... 10xxxxxx.

Это означает, что кодировка каждого символа Unicode содержит либо один 0xxxxxxxбайт, либо один 11xxxxxxбайт и от 1 до 510xxxxxx байтов.

Разделив все байты ввода на 64 , мы превращаемся 0xxxxxxxв 0 или 1 , 11xxxxxxв 3 и 10xxxxxxв 2 .

Если мы сравним частное с 2 - нажатие 1 на 2 ; и 0 для 0 , 1 и 3 - каждый символ будет превращен в 0 , а затем от 1 до 5 1 .

Все , что осталось , чтобы разделить полученную строку на вхождениях 0 , сосчитать число 1 «S между этими нулями и добавьте к сумме.

Как это работает

{     }%          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 байт

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

NB

Хорошо, это должно сработать и работает почти во всех тестовых случаях, за исключением тех, 𩸽которые как-то учитываются 3,3на моей машине. Этот символ даже отображается как 7 байт на моем компьютере. Я подозреваю, что это связано с какой-то ошибкой в ​​версии для Windows или .NET, которую я использую локально, поскольку у @Mego такой проблемы нет . ( Правка: @cat указывает, что это из-за спецификации . Спасибо за разгадку этой загадки, @cat! )

Тем не менее, это еще не все проблемы. Я думаю, что знаю, откуда возникают некоторые проблемы. Внутри .NET все строки состоят из кодовых блоков UTF-16 (типа System.Char). Благодаря очень свободной настройке типов, которую использует PowerShell, существует много неявных приведений и преобразований между типами в фоновом режиме. Вероятно, это является фактором, влияющим на поведение, которое мы наблюдаем - например, [system.text.encoding]::utf8.getchars([System.Text.UTF8Encoding]::UTF8.GetBytes('𩸽'))возвращает два непечатаемых, а не один символ.


объяснение

Очень простой код. Принимает входные данные $args[0]и явно преобразует их как массив символов, чтобы мы могли циклически проходить через каждый компонент строки |%{...}. На каждой итерации мы используем вызов .NET [System.Text.Encoding]::UTF8.GetByteCount()( System.подразумевается) для получения количества байтов текущего символа $_. Это размещается на конвейере для последующего вывода. Так как это коллекция[int] возвращаемых s, приведение к массиву неявно.

Тестовые прогоны

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

Отредактировано, чтобы добавить Это правильно учитывает требование нулевых байтов, которое было добавлено к проблеме после того, как я первоначально отправил, при условии, что вы извлекаете данные из текстового файла и передаете их следующим образом:

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.Да, это из-за Byte-Order Mark, который вы получаете в Windows с UTF-8. Скажите Notepad ++ об использовании UTF-8 without BOM(как вы всегда должны избегать BOM , особенно для совместимости с Unicies), и вы обнаружите, что файл имеет размер 4 байта, потому что BOM 3 и 4 + 3 = 7
cat

@ Cat Ах, да, это имеет смысл. Итак, это объясняет разницу в размерах файлов. Тем не менее, это по-прежнему не учитывает различное поведение внутри самой оболочки. Например, сохранение его как UTF-8 без спецификации и запуск по- get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}прежнему возвращает 3,3.
AdmBorkBork



6

JavaScript (ES6), 54 45 43 байта

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

Редактировать: 2 байта сохранены с помощью @ l4m2.


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

@ l4m2 Это не работает для не-BMP персонажей, но я смог это исправить.
Нил


5

Perl 6 ,  77 69  63 байта

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

Поскольку в Perl 6 используются строки NFG, я должен напрямую извлекать байты, что обходит функцию.
(NFG похож на NFC за исключением того, что он также создает синтетические составные кодовые точки)

Вывод разделен символами новой строки.

Тест:

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)

Объяснение:

# 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

Это работает, потому что первый байт в многобайтовой кодовой точке имеет количество байтов, закодированных внутри него, а другие байты в кодовой точке имеют самый старший установленный бит, но не следующий старший. В то время как однобайтовые кодовые точки не имеют старшего установленного бита.


Не можете сделать read:1и / или /while$вместо этого? И если это работает if$,?
Эрик Outgolfer

@ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ Нет, потому что это будет восприниматься как нечто иное. Я могу удалить пространство раньше, whileхотя.
Брэд Гилберт b2gills

Можете ли вы объяснить контрмеры NFG?
JDługosz

Если я передаю NUL-байт в STDIN этой программы, он печатает \n1\n1\n, это намеренно? В основном это обрабатывает NUL байты?
кот

@cat Почему бы и нет? Когда я делаю это: perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'я получаю 4␤1␤4так, как я ожидал. (Часть о nuls была добавлена ​​после того, как я написал)
Брэд Гилберт b2gills

5

Python 3, 82 байта

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

Это намного длиннее, чем в другом ответе на Python и в большинстве других ответов, но использует подход с использованием логарифмов, которого я еще не видел.

Анонимная функция, которая принимает входные данные через аргумент в виде строки и возвращает список.

Попробуйте это на Ideone

Как это работает

Этот метод основан на способе, которым UTF-8 кодирует кодовую точку символа. Если кодовая точка меньше 128, символ кодируется как в ASCII:

0xxxxxxx

где xпредставляет биты кодовой точки. Однако для кодовых точек, больших или равных 128, первый байт дополняется тем же числом 1s, что и общее количество байтов, и начинаются последующие байты 10. Затем вводятся биты кодовой точки, чтобы получить кратчайшую возможную многобайтовую последовательность, и становятся все оставшиеся биты 0.

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

и так далее.

Теперь можно заметить, что для каждого количества байтов n верхний предел количества битов кодовой точки определяется как (-n+7)+6(n-1) = 5n+1. Следовательно, верхний предел кодовой точки cдля каждого nопределяется в десятичном виде как c= 2^(5n+1). Перестановка это даетn = (log2(c)-1)/5 . Таким образом, для любой кодовой точки, число байтов может быть найдено путем оценки вышеприведенного выражения, а затем взяв верхний предел.

Тем не менее, это не работает для кодовых точек в диапазоне 64 <= c <= 127 , поскольку отсутствие дополнения 1из-за ASCII-подобной кодировки для 1-байтовых символов означает, что неверный верхний предел предсказан и log2не определен c = 0, что происходит, если нулевой байт присутствует на входе. Следовательно, если c <= 127значение 1возвращается для n.

Это именно то, что делает код; для каждого символа iв строке xкодовая точка находится с помощью ordфункции, а верхний предел выражения - с помощью целочисленного, а не с плавающим делением с 5последующим добавлением 1. Поскольку тип с плавающей точкой в ​​Python всегда представляет целые числа, так как x.0даже после целочисленного деления результат передается intфункции для удаления завершающего нуля. Еслиord(i) <= 127 , логическое короткое замыкание означает, что 1вместо этого возвращается. Количество байтов для каждого символа сохраняется как элемент в списке, и этот список возвращается.


5

Java 10, 100 96 95 67 61 байт

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

-4 байта, удаляя пробелы, потому что это разрешено в комментариях,
-1 байт меняется UTF-8на utf8
-28 байт при переходе с Java на 7 - 8 ( a->{...}вместо void c(char[]i)throws Exception{...})
-3 байта, принимая входные данные как массив строк вместо символьного массива, и
-3 байта переходя с Java 8 на 10 ( varвместоString )

Объяснение:

Попробуйте онлайн.

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

Это работает для нулевых байтов?
кот

@cat Контрольный пример для нулевых байтов был добавлен позже. Но да, это также работает для нулевых байтов, и я добавил тестовый пример.
Кевин Круйссен

3

Юлия, 34 байта

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

Это анонимная функция, которая принимает строку и возвращает целочисленный массив. Чтобы вызвать его, присвойте его переменной.

Подход довольно прост: если вход пустой, выход пустой. В противном случае мы отображаемsizeof функцию, которая считает количество байтов в строке, с каждой односимвольной подстрокой.

Попробуйте онлайн! (включает все тестовые случаи)


s->[sizeof("$c")for c=s]сохраняет несколько байтов.
Деннис

Странный; ничего split("","")не возвращает []? (JavaScript "".split("")делает.)
Нил

@Neil, split("","")кажется, дает ""(в отличие от Python, который дает исключение), но я ничего не знаю о совместимости []и ""в julia.
кот

@Neil Нет, split("", "") == [""]то есть одноэлементный массив, содержащий пустую строку, но проблема в том sizeof("") == 0, что, как сказал OP, недопустимо.
Алекс А.

@Dennis Это не удастся для неиндексируемых строк. (Хотя я не могу придумать пример от руки.)
Алекс А.

3

PHP, 92 57 байт

Во-вторых, вы можете сделать это с гораздо меньшими усилиями:

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

Попробуйте онлайн, обратите внимание, что это немного дольше, поскольку он использует стандартный ввод, а не программный аргумент.
Эта версия требует, чтобы вы игнорировали уведомления, отправленные на stderr, но это нормально .

старая версия:
использует другой подход к другому php-ответу. Полагается на отсутствие встроенной поддержки многобайтовых строк в php.

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

Хороший ответ! Я думаю, что вы можете полностью удалить открывающий тег или изменить его на<?=
cat

Без тега это фрагмент кода, а не программа, и даже если это разрешено, я чувствую себя немного грязно. С альтернативным тегом вы получаете ошибку разбора (или, по крайней мере, я сделал это на php 5.5, к чему я привык).
user55641

Хорошо :) Я не знаю PHP (и не хочу, кашель ), но я укажу
кошка

3

Emacs Lisp, 55 49 байт

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

Сначала разбивает строку в список символов с помощью (mapcar 'string s). stringФункция Emacs Lisp принимает список символов и строит строку из них. Из-за способа, которым Emacs разбивает строки mapcar(т.е. в список целых чисел, а не символов или строк), это явное преобразование необходимо. Затем отображает string-bytesфункцию в этот список строк.

Пример:

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

Старый ответ:

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

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


Что произойдет, nilесли вы сгладите результат?
Адам

1
@ Adám nil- пустой список (и единственный способ сказать «ложь» в Emacs). Хотя в Emacs нет стандартного сглаживания (вы можете использовать тире -flatten), любая возможная реализация его устранит.
Лорд Юма

3

JavaScript (узел), 27 байт

s=>s.map(Buffer.byteLength)

Он принимает входные данные в виде массива отдельных символов и возвращает массив счетчиков байтов.

Bufferметод представления необработанных двоичных данных Buffer.byteLength (строка) дает количество байтов в строке. UTF-8 является кодировкой по умолчанию. Обратите внимание, что только Node.js имеет буферы, а не браузер JS. Грубый эквивалент браузера называется Blob , который занимает 31 байт:

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

Тест

Сохраните этот файл и запустите его через узел или попробуйте онлайн .

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

Это должно быть результатом:

$ 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

Баш, 74 байта

Golfed

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

Алгоритм

hexdump входная строка, сложить 2 символа в строке, вырезать только первый символ

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

2
c
b
e
8
a
f
a
b
b

(4 старших бита каждого входного байта в виде шестнадцатеричного символа, по одному на строку)

Удалить "байты продолжения" 0x80..0xBF

tr -d '89ab'

2
c

e


f

(что осталось, это 4 бита первого байта каждого символа Юникода)

сопоставьте первые биты с длиной символа, сверните вывод и напечатайте

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

1 2 3 4

Тест

 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 Хороший подход. Вы на самом деле читаете результат прямо из ввода.
Адам

-tВариант trбыл мне незнаком, и, по- видимому расширение GNU. Трубопровод к подстановке команд после echoможет также стоить немного более подробного объяснения.
tripleee


2

C #, 89 82 байта

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

Простая лямбда C #, которая перебирает строку и возвращает разделенный пробелами список.

Редактировать: сохранено 6 байтов благодаря некоторым очень хорошим комментариям.


почти уверен, что вы можете сделатьvar J="";...
кошка

Кроме того, OP указывает в комментарии, что вам не нужно разделять вывод пробелами, 1121и 1 2 1 2оба в порядке
cat

1
@cat Спасибо, спасли мне 6 байтов
AstroDan

Кроме того, у вас есть дополнительное место в} return J;};
кошка

Похоже, вам нужно using System.Text или около того - импорт не является бесплатным.
кошка

2

Haskell, 85 байт

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

Немного поздно, но это будет короче, какmap$...
H.PWiz


1

C 85 байт.

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

Исследует старшие 4 бита каждого байта, чтобы определить кодирование и количество последующих байтов, которые нужно пропустить;


Это работает на нулевых байтах?
кот

Да, while *c выходы в пустой строке, и `c + = d 'пропускает нули в середине многобайтовой кодовой точки.
AShelly

1
Это неверно Конец строки ( char*действительно) в C помечен нулевым байтом. Невозможно отличить нулевые байты от фактического конца строки.
Деннис

@Dennis Именно потому, что нет никакой разницы :)
кошка

1
ОП указал в комментарии (и теперь он в посте), что вы можете запросить длину строки в байтах в качестве аргумента, так что сделайте это, и это снова будет действительным
cat

1

Фактор 57 87 82 80 байт

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

Разъяснение:

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

Модульные тесты:

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

Они все проходят, сейчас. с:


1

Swift 2,2, 67 52 50 байт

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

Ужасно некрасиво В Swift нет способа получить длину символа в UTF-8, поэтому мне нужно перебрать строку за символом, преобразовать в Charactera Stringи найти countэтот единственный символString (эй, по крайней мере, есть встроенный способ сделать это). Нужны оптимизации, возможно, с помощью сканера.

Редакция 1. Сохранено 15 байт с помощью count вместоunderestimateCount() .

Редакции 2: Сохранены еще 2 символа с помощью цикла for-in вместо a для каждого замыкания.


1

Ржавчина, 53 байта

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

В Rust есть примитивы, итераторы и лямбды utf-8, так что все было просто. Тестовый код:

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

Выходы

1211133112111114444 

1

JQ, 26 символов

(23 символа кода + 3 символа командной строки)

(./"")[]|utf8bytelength

Надеюсь, конкурирует. Хотя utf8bytelengthбыло добавлено 9 ++ месяцев до этого вопроса, он все еще не включен в выпущенную версию.

Образец прогона:

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 байт

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

Входные данные - это массив байтов.

Количество байтов в символе UTF-8 равно количеству старших 1битов в первом байте (если нет 1s, в этом случае символ равен 1 байту). Чтобы найти число ведущих 1, программа находит первое 0в двоичном представлении, а затем добавляет 1, если это было 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 байт

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

Технически, s - это последовательность символов, но оказывается, что есть неявное преобразование, которое позволяет передавать строку.

При тестировании этого в консоли с !±≡𩸽 он разбивает кандзи на два символа, каждый длиной 3 байта. Все остальные тестовые случаи работают нормально.

Редактировать: Оказывается, что импорт общего пространства имен не является неявным. До еще 12 символов.


1) Ответ PowerShell от Тимми Д. имеет ту же проблему 6 байтов на кандзи. Я бы объяснил это тем, что Windows была глупой и бесполезной в Unicode. 2) Если вы получаете 6 байтов для кандзи при чтении из файла, в который добавлен файл, UTF-8 without BOMто это неправильно и должно быть исправлено. 3) Похоже , F # нужны заявления , как let f(x)= ...закончиться ;;, как SML. 4) Вы можете оставить от назначения этой анонимной функции имени, то есть (s)=seq{for c in s->Encoding.UTF8.GetByteCount([|c|])}.
кошка

Кроме того, я получаю error FS0039: The namespace or module 'Encoding' is not definedпри попытке запустить это. Что я делаю не так?
кот

Кроме того, добро пожаловать в Программирование Пазлов и Code Golf, это хороший первый ответ! : D
кошка

@cat Вам нужно открыть System.Textпространство имен. Я предполагаю, что пространство имен открывается и входной код включен, исходя из C # ответа AstroDan.
закрытый интерфейс

Вы должны посчитать байты любого import, #include, open, load, require, using, и USING:т.д. здесь PPCG. Ответ AstroDan на C # также ошибочен, и я уведомил их об этом.
кошка

1

05AB1E , 15 байтов

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

Попробуйте онлайн.
Заголовокεиспользуется для каждого из всех тестовых случаев;
Нижний колонтитулï]J]»для симпатичной печати выходных списков символов (ï: десятичные дроби и символы в целые числа;:]закрыть if-else и for-eachJ;: объединить цифры вместе};: закрыть заголовок foreach;» помощью новых строк).

Объяснение:

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

Поскольку 05AB1E не имеет встроенных функций для преобразования символов в количество используемых байтов, я использую их Çдля преобразования символов в их значения в Юникоде, а для каждого из них в псевдокоде выполните следующие действия:

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

Вдохновленный ответом @TheBikingViking 's Python 3 .


0

Zsh , 41 байт

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

Попробуйте онлайн!

Zsh поддерживает UTF-8, поэтому мы разбиваем строку на символы, затем отключаем многобайтовую и печатаем длину каждого символа.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.