задача
Учитывая, что строка UTF-8 (любыми средствами) отвечает (любыми средствами) эквивалентному списку, где каждый элемент - это число байтов, используемых для кодирования соответствующего входного символа.
Примеры
!
→ 1
Ciao
→ 1 1 1 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
(нулевой байт) → 1
Нулевые байты
Если единственный способ сохранить входные данные после нулевых байтов - узнать общее количество байтов, вы можете получить количество байтов любым способом (даже пользовательским вводом).
Если ваш язык вообще не может обрабатывать нулевые байты, вы можете предположить, что входные данные не содержат нулевых значений.
Ответы:
Пиф,
97 байтСпасибо @Maltysen за сохранение 2 байта!
Тестирование
Преобразует каждый символ входных данных в его двоичное представление, а затем разбивает его на куски длиной 8. Затем количество этих кусочков - это количество байтов, необходимое для кодирования этого символа.
источник
.E
pyth.herokuapp.com/…mlhc8.B
ml%8.B
(теперьd
это неявно).Python 3,
4236 байтисточник
map
.lambda x:map(len,map(str.encode,x))
C
6865 байтСпасибо @FryAmTheEggman за 3 байта!
Проверьте это на Ideone .
источник
APL, 15 символов
На английском языке: преобразовать каждый символ в UTF-8 (что означает: вектор представления байтов) и получить его счет.
источник
≢¨'UTF-8'∘⎕ucs¨
+⌿0 7 11 16∘.≤2⍟⎕UCS
0 7 11 16⍸2⍟⎕UCS
GolfScript, 16 байт
Попробуйте онлайн!
Задний план
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 между этими нулями и добавьте к сумме.
Как это работает
источник
PowerShell v4, 58 байт
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, приведение к массиву неявно.Тестовые прогоны
Отредактировано, чтобы добавить Это правильно учитывает требование нулевых байтов, которое было добавлено к проблеме после того, как я первоначально отправил, при условии, что вы извлекаете данные из текстового файла и передаете их следующим образом:
источник
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 = 7get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}
прежнему возвращает3,3
.-Encoding
Параметр не появляется в поддержке .JavaScript (ES6),
544543 байтаРедактировать: 2 байта сохранены с помощью @ l4m2.
источник
s=>[...s].map(c=>encodeURI(c).length/3-4&3)
Рубин, 33 байта
Едва выгибает Python, ура! Попробуйте онлайн.
источник
Perl 6 ,
77 6963 байтаПоскольку в Perl 6 используются строки NFG, я должен напрямую извлекать байты, что обходит функцию.
(NFG похож на NFC за исключением того, что он также создает синтетические составные кодовые точки)
Вывод разделен символами новой строки.
Тест:
Объяснение:
Это работает, потому что первый байт в многобайтовой кодовой точке имеет количество байтов, закодированных внутри него, а другие байты в кодовой точке имеют самый старший установленный бит, но не следующий старший. В то время как однобайтовые кодовые точки не имеют старшего установленного бита.
источник
read:1
и / или/while$
вместо этого? И если это работаетif$
,?while
хотя.\n1\n1\n
, это намеренно? В основном это обрабатывает NUL байты?perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'
я получаю414
так, как я ожидал. (Часть о nuls была добавлена после того, как я написал)Python 3, 82 байта
Это намного длиннее, чем в другом ответе на Python и в большинстве других ответов, но использует подход с использованием логарифмов, которого я еще не видел.
Анонимная функция, которая принимает входные данные через аргумент в виде строки и возвращает список.
Попробуйте это на Ideone
Как это работает
Этот метод основан на способе, которым UTF-8 кодирует кодовую точку символа. Если кодовая точка меньше 128, символ кодируется как в ASCII:
где
x
представляет биты кодовой точки. Однако для кодовых точек, больших или равных 128, первый байт дополняется тем же числом1
s, что и общее количество байтов, и начинаются последующие байты10
. Затем вводятся биты кодовой точки, чтобы получить кратчайшую возможную многобайтовую последовательность, и становятся все оставшиеся биты0
.и так далее.
Теперь можно заметить, что для каждого количества байтов
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
вместо этого возвращается. Количество байтов для каждого символа сохраняется как элемент в списке, и этот список возвращается.источник
Java 10,
10096956761 байт-4 байта, удаляя пробелы, потому что это разрешено в комментариях,
-1 байт меняется
UTF-8
наutf8
-28 байт при переходе с Java на 7 - 8 (
a->{...}
вместоvoid c(char[]i)throws Exception{...}
)-3 байта, принимая входные данные как массив строк вместо символьного массива, и
-3 байта переходя с Java 8 на 10 (
var
вместоString
)Объяснение:
Попробуйте онлайн.
источник
Юлия, 34 байта
Это анонимная функция, которая принимает строку и возвращает целочисленный массив. Чтобы вызвать его, присвойте его переменной.
Подход довольно прост: если вход пустой, выход пустой. В противном случае мы отображаем
sizeof
функцию, которая считает количество байтов в строке, с каждой односимвольной подстрокой.Попробуйте онлайн! (включает все тестовые случаи)
источник
s->[sizeof("$c")for c=s]
сохраняет несколько байтов.split("","")
не возвращает[]
? (JavaScript"".split("")
делает.)split("","")
кажется, дает""
(в отличие от Python, который дает исключение), но я ничего не знаю о совместимости[]
и""
в julia.split("", "") == [""]
то есть одноэлементный массив, содержащий пустую строку, но проблема в томsizeof("") == 0
, что, как сказал OP, недопустимо.PHP,
9257 байтВо-вторых, вы можете сделать это с гораздо меньшими усилиями:
Попробуйте онлайн, обратите внимание, что это немного дольше, поскольку он использует стандартный ввод, а не программный аргумент.
Эта версия требует, чтобы вы игнорировали уведомления, отправленные на stderr, но это нормально .
старая версия:
использует другой подход к другому php-ответу. Полагается на отсутствие встроенной поддержки многобайтовых строк в php.
источник
<?=
Emacs Lisp,
5549 байтСначала разбивает строку в список символов с помощью
(mapcar 'string s)
.string
Функция Emacs Lisp принимает список символов и строит строку из них. Из-за способа, которым Emacs разбивает строкиmapcar
(т.е. в список целых чисел, а не символов или строк), это явное преобразование необходимо. Затем отображаетstring-bytes
функцию в этот список строк.Пример:
Testcases:
Старый ответ:Ungolfed:
Testcases:
источник
nil
если вы сгладите результат?nil
- пустой список (и единственный способ сказать «ложь» в Emacs). Хотя в Emacs нет стандартного сглаживания (вы можете использовать тире-flatten
), любая возможная реализация его устранит.JavaScript (узел), 27 байт
Он принимает входные данные в виде массива отдельных символов и возвращает массив счетчиков байтов.
Buffer
метод представления необработанных двоичных данных Buffer.byteLength (строка) дает количество байтов в строке. UTF-8 является кодировкой по умолчанию. Обратите внимание, что только Node.js имеет буферы, а не браузер JS. Грубый эквивалент браузера называется Blob , который занимает 31 байт:Тест
Сохраните этот файл и запустите его через узел или попробуйте онлайн .
Это должно быть результатом:
источник
Баш, 74 байта
Golfed
Алгоритм
hexdump входная строка, сложить 2 символа в строке, вырезать только первый символ
(4 старших бита каждого входного байта в виде шестнадцатеричного символа, по одному на строку)
Удалить "байты продолжения" 0x80..0xBF
(что осталось, это 4 бита первого байта каждого символа Юникода)
сопоставьте первые биты с длиной символа, сверните вывод и напечатайте
Тест
источник
-t
Вариантtr
был мне незнаком, и, по- видимому расширение GNU. Трубопровод к подстановке команд послеecho
может также стоить немного более подробного объяснения.PHP, 126 байт
Попробуйте онлайн!
источник
<?=($s=fgets(STDIN))?
C #,
8982 байтаПростая лямбда C #, которая перебирает строку и возвращает разделенный пробелами список.
Редактировать: сохранено 6 байтов благодаря некоторым очень хорошим комментариям.
источник
var J="";...
1121
и1 2 1 2
оба в порядке} return J;};
using System.Text
или около того - импорт не является бесплатным.Haskell, 85 байт
источник
map$...
Pyth, 17 байт
Попробуйте онлайн!
Используйте кодовую точку символов с некоторой арифметикой.
источник
C 85 байт.
Исследует старшие 4 бита каждого байта, чтобы определить кодирование и количество последующих байтов, которые нужно пропустить;
источник
while *c
выходы в пустой строке, и `c + = d 'пропускает нули в середине многобайтовой кодовой точки.char*
действительно) в C помечен нулевым байтом. Невозможно отличить нулевые байты от фактического конца строки.Фактор
57878280 байтРазъяснение:
Модульные тесты:
Они все проходят, сейчас. с:
источник
Swift 2,2,
675250 байтУжасно некрасиво В Swift нет способа получить длину символа в UTF-8, поэтому мне нужно перебрать строку за символом, преобразовать в
Character
aString
и найтиcount
этот единственный символString
(эй, по крайней мере, есть встроенный способ сделать это). Нужны оптимизации, возможно, с помощью сканера.Редакция 1. Сохранено 15 байт с помощью
count
вместоunderestimateCount()
.Редакции 2: Сохранены еще 2 символа с помощью цикла for-in вместо a для каждого замыкания.
источник
Ржавчина, 53 байта
В Rust есть примитивы, итераторы и лямбды utf-8, так что все было просто. Тестовый код:
Выходы
источник
JQ, 26 символов
(23 символа кода + 3 символа командной строки)
Надеюсь, конкурирует. Хотя
utf8bytelength
было добавлено 9 ++ месяцев до этого вопроса, он все еще не включен в выпущенную версию.Образец прогона:
источник
C (gcc) , 53 байта
Попробуйте онлайн!
источник
SmileBASIC, 69 байт
Входные данные - это массив байтов.
Количество байтов в символе UTF-8 равно количеству старших
1
битов в первом байте (если нет1
s, в этом случае символ равен 1 байту). Чтобы найти число ведущих 1, программа находит первое0
в двоичном представлении, а затем добавляет 1, если это было 0.источник
F #,
595466 байтТехнически, s - это последовательность символов, но оказывается, что есть неявное преобразование, которое позволяет передавать строку.
При тестировании этого в консоли с
!±≡𩸽
он разбивает кандзи на два символа, каждый длиной 3 байта. Все остальные тестовые случаи работают нормально.Редактировать: Оказывается, что импорт общего пространства имен не является неявным. До еще 12 символов.
источник
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
при попытке запустить это. Что я делаю не так?System.Text
пространство имен. Я предполагаю, что пространство имен открывается и входной код включен, исходя из C # ответа AstroDan.import
,#include
,open
,load
,require
,using
, иUSING:
т.д. здесь PPCG. Ответ AstroDan на C # также ошибочен, и я уведомил их об этом.05AB1E , 15 байтов
Попробуйте онлайн.
Заголовок
ε
используется для каждого из всех тестовых случаев;Нижний колонтитул
ï]J]»
для симпатичной печати выходных списков символов (ï
: десятичные дроби и символы в целые числа;:]
закрыть if-else и for-eachJ
;: объединить цифры вместе}
;: закрыть заголовок foreach;»
помощью новых строк).Объяснение:
Поскольку 05AB1E не имеет встроенных функций для преобразования символов в количество используемых байтов, я использую их
Ç
для преобразования символов в их значения в Юникоде, а для каждого из них в псевдокоде выполните следующие действия:Вдохновленный ответом @TheBikingViking 's Python 3 .
источник
Zsh , 41 байт
Попробуйте онлайн!
Zsh поддерживает UTF-8, поэтому мы разбиваем строку на символы, затем отключаем многобайтовую и печатаем длину каждого символа.
источник