Байти / Характер


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

Pyth, 9 7 байт

Дякуємо @Maltysen за збереження 2 байтів!

mlc.Bd8

Тестовий набір

Перетворює кожен символ вхідного сигналу у його бінарне подання, а потім розбиває його на шматки довжиною 8. Кількість цих фрагментів - це кількість байтів, необхідних для кодування цього символу.


1
ви можете зберегти 2 байти з розділенням, а не діленням, а потім видаленням .E pyth.herokuapp.com/…
Maltysen

@Maltysen Це розумно, дякую!
Денкер

1
Відповідь такої ж довжини, що спирається на аналогічну хитрість:mlhc8.B
FryAmTheEggman

@LeakyNun тоді було б просто дати тестовий випадок, який не вдається, чи не так?
Лоза

Щоб зберегти ще один байт, замість того, щоб розділяти на шматки 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 ... Привіт.
lstefano

Цікавий (але триваліший) підхід на основі масиву:+⌿0 7 11 16∘.≤2⍟⎕UCS
Adám

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

7

GolfScript, 16 байт

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

Спробуйте в Інтернеті!

Фон

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

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

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

  • Усі інші кодові точки кодуються як 11xxxxxx 10xxxxxx ... 10xxxxxx.

Це означає, що кодування кожного символу Unicode містить або один 0xxxxxxxбайт, або один 11xxxxxxбайт і від 1 до 5 10xxxxxxбайт.

Ділимо всі байти вхідного сигналу на 64 , перетворюємо 0xxxxxxxна 0 або 1 , 11xxxxxxна 3 і 10xxxxxxна 2 .

Якщо порівняти коефіцієнт з 2 - натискання 1 на 2 ; і 0 для 0 , 1 і 3 - кожен символ буде перетворений на 0 , а потім 1 - 5 1 's.

Залишилося розділити отриманий рядок при входах 0 , підрахувати число 1 до цих нулів і додати його до суми.

Як це працює

{     }%          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 вказує, що це пов'язано з BOM . Дякую за розв’язання цієї таємниці, @cat! )

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


Пояснення

Дуже простий код. Бере вхід $args[0]і явно передає його як масив char, щоб ми могли перебирати кожен компонент рядка |%{...}. Кожну ітерацію ми використовуємо .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. Скажіть Блокноту ++ використовувати UTF-8 without BOM(як завжди слід уникати BOM , особливо для сумісності з Unicies), і ви знайдете, що файл має розмір 4 байти, тому що BOM - 3, а 4 + 3 = 7
кіт

@cat Ага, так, це має сенс. Гаразд, щоб обліковувати різницю у розмірах файлів. Однак це все ще не пояснює різну поведінку всередині самої оболонки. Наприклад, збереження його як UTF-8 без BOM, а запуск 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)
l4m2

@ 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$,?
Ерік Аутгольфер

@ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ Ні, тому що це буде розбиратися як щось інше. whileОднак я можу видалити пробіл раніше .
Бред Гілберт b2gills

Чи можете ви пояснити контрзаходи NFG?
JDługosz

Якщо я повторюю байт NUL до STDIN цієї програми, він друкує \n1\n1\n, це навмисно? По суті, чи обробляє це байти NUL?
кіт

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

5

Пітон 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, значення 1n повертається для 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 байти, приймаючи вхід як String-масив замість масиву символів, і
-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, що, за словами ОП, заборонено.
Алекс А.

@Dennis Це не вдасться для рядків, що не індексуються. (Не можу придумати приклад на відстані.)
Алекс А.

3

PHP, 92 57 байт

По-друге, ви можете зробити це за допомогою набагато меншого фальсифікацію:

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

Спробуйте в Інтернеті, зауважте, що це трохи довше, оскільки він використовує stdin, а не програмний аргумент.
Ця версія вимагає від вас ігнорувати повідомлення, надіслані stderr, але це нормально .

стара версія:
Використовує досить інший підхід до відповіді на інший php. Покладається на відсутність вбудованої підтримки багатобайтових рядків у php.

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

Гарна відповідь! Я думаю, ви можете повністю скинути вступний тег або змінити його на<?=
кот

Без тегу це фрагмент коду, а не програма, і навіть якщо це дозволено, це змушує мене почуватись невиразно брудним. За допомогою альтернативного тегу ви отримуєте помилку розбору (принаймні, я робив на php 5.5, до чого я звик).
користувач55641

Гаразд :) Я не знаю PHP (і не хочу кашляти ), але я накажу вам тут: codegolf.stackexchange.com/questions/2913
кіт

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) 

Тести:

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

Безголівки:

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

Тести:

(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якщо ви вирівняєте результат?
Adám

1
@ Adám nil- це порожній список (і єдиний спосіб сказати "false" в 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 байти

Гольф

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

Алгоритм

шістнадцятковий вхідний рядок, складіть 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 біти першого байта кожного символу unicode)

зіставити перші біти в діаграму, згортати вихід і друкувати

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також може бути вартим дещо більш детального пояснення.
трійчатка


2

C #, 89 82 байт

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

Проста C # лямбда, яка переходить через рядок і повертає розділений між собою пробіл.

Редагувати: збережено 6 байтів завдяки дуже приємним коментарям.


майже впевнений, що ви можете зробитиvar J="";...
кіт

Крім того, в коментарі ОП зазначає, що не потрібно розділяти вихідний пробіл, 1121і 1 2 1 2вони обоє в порядку
кіт

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
ОП заявив у коментарі (і це зараз у публікації), що ви можете запитувати довжину рядка в байтах як аргумент, так що зробіть це, і це буде дійсно знову
кіт

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

Вони всі проходять, зараз. c:


1

Швидкий 2.2, 67 52 50 байт

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

Жахливо потворно. Немає способу отримати довжину символу UTF-8 у Swift, тому мені потрібно повторити рядок за символом, перетворити в 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())}

Іржа має utf-8 char примітиви, ітератори та лямбда, тож це було просто. Код тесту:

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 байту). Щоб знайти кількість провідних 1s, програма знаходить перше 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) Відповідь Тіммі Д. має ті ж проблеми, що мають 6 байтів на канджі. Я б відніс це тим, що Windows є німим і марним в Unicode. 2) Якщо ви отримуєте 6 байт для канджі, читаючи з файлу enocded з, 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коли намагаюся запустити це. Що я роблю неправильно?
кіт

Крім того, ласкаво просимо до головоломки програмування та коду для гольфу, це хороша перша відповідь! : D
кіт

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

Ви повинні порахувати байти будь-якого import, #include, open, load, require, using, і USING:т.д. тут PPCG. Відповідь AstroDan на C # аналогічно помилкова, і я повідомив їх про це.
кіт

1

05AB1E , 15 байт

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

Спробуйте в Інтернеті.
Заголовокεвикористовується для кожного для всіх тестових випадків;
Footerï]J]»на досить-друку вихідних символів списків (ï: десяткові і символів в цілі числа;]: закритиякщо-ще й Еогеасп;J: Join цифри разом;}: близький заголовок Еогеасп;»: Реєстрація нових ліній).

Пояснення:

Ç                   # 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 не має вбудованих символів для перетворення символів у кількість використаних байтів, я використовую Çдля перетворення символів у їхні значення коду unicode, а для кожного з них виконайте наступне у псевдокоді:

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

Натхненний відповіддю @TheBikingViking Python 3 .


Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.