Byte / Ký tự


28

Bài tập

Đưa ra một chuỗi UTF-8 (bằng mọi cách) câu trả lời (bằng mọi cách) một danh sách tương đương trong đó mọi phần tử là số byte được sử dụng để mã hóa ký tự đầu vào tương ứng.

Ví dụ

!1

Ciao1 1 1 1

tʃaʊ1 2 1 2

Adám1 1 2 1

ĉaŭ2 1 2(ký tự đơn)

ĉaŭ1 2 1 1 2(sử dụng kết hợp lớp phủ)

チャオ3 3 3

(đầu vào trống) → (đầu ra trống)

!±≡𩸽1 2 3 4

(Một byte rỗng) → 1

Null byte

Nếu cách duy nhất để tiếp tục đọc đầu vào ngoài byte rỗng là bằng cách biết tổng số byte, bạn có thể lấy số byte bằng bất kỳ phương tiện nào (ngay cả đầu vào của người dùng).

Nếu ngôn ngữ của bạn hoàn toàn không thể xử lý byte rỗng, bạn có thể cho rằng đầu vào không chứa null.


1
Nếu đầu vào trống, chúng ta có thể xuất 0 hoặc giá trị falsey khác không?
Alex A.

2
Tôi có thể in số byte mà không tách? Giá trị cao nhất có thể là 6, vì vậy nó không rõ ràng.
Dennis

3
Chúng ta có phải hỗ trợ byte rỗng không? Đó có thể là một nỗi đau thực sự trong một số ngôn ngữ ...
Dennis

3
Bạn nên thêm nó vào bài viết. Tôi không biết hầu hết các ngôn ngữ đủ tốt để nói nếu nó tạo ra sự khác biệt, nhưng tôi nghĩ rằng nó làm mất hiệu lực ít nhất hai trong số các câu trả lời.
Dennis

2
@ Adám thì có. Ví dụ, trong C, chuỗi C kết thúc bằng byte NUL, vì vậy bạn dừng đọc ngay khi tìm thấy. Nếu bạn biết độ dài của chuỗi, bạn dừng đọc sau nhiều byte, NUL và tất cả.
con mèo

Câu trả lời:


10

Bình thường, 9 7 byte

Cảm ơn @Maltysen vì đã tiết kiệm 2 byte!

mlc.Bd8

Bộ kiểm tra

Chuyển đổi mọi ký tự của đầu vào thành biểu diễn nhị phân của nó và sau đó chia phần này thành các đoạn có độ dài 8. Số lượng các đoạn đó sau đó là lượng byte cần thiết để mã hóa ký tự đó.


1
bạn có thể lưu 2 byte bằng cách chia thay vì chia và sau đó xóa .E pyth.herokuapp.com/,
Maltysen

@Maltysen Thật thông minh, cảm ơn!
Denker

1
Câu trả lời có cùng độ dài dựa trên một mẹo tương tự:mlhc8.B
FryAmTheEggman

@LeakyNun thì sẽ là một điều đơn giản để đưa ra một trường hợp thử nghiệm thất bại, phải không?

Để lưu một byte khác, thay vì chia thành 8 phần, hãy lấy số 8: ml%8.B(bây giờ dlà ẩn).
Anders Kaseorg


11

C, 68 65 byte

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

Cảm ơn @FryAmTheEggman vì đã chơi golf 3 byte!

Kiểm tra nó trên Ideone .


11

APL, 15 ký tự

≢¨'UTF-8'∘⎕ucs¨

Trong tiếng Anh: chuyển đổi từng ký tự thành UTF-8 (có nghĩa là: vectơ biểu diễn byte) và lấy số liệu của nó.


Lưu một byte:≢¨'UTF-8'∘⎕ucs¨
Adám

Thật vậy @ Adám ... Chúc mừng.
lstefano

Một cách tiếp cận dựa trên mảng thú vị (nhưng dài hơn):+⌿0 7 11 16∘.≤2⍟⎕UCS
Adám

Phiên bản 16.0:0 7 11 16⍸2⍟⎕UCS
Adám

7

GolfScript, 16 byte

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

Hãy thử trực tuyến!

Lý lịch

GolfScript không biết Unicode là gì; tất cả các chuỗi (đầu vào, đầu ra, bên trong) được tạo thành từ các byte. Mặc dù điều đó có thể khá khó chịu, nhưng nó hoàn hảo cho thử thách này.

UTF-8 mã hóa các ký tự ASCII và không phải ASCII khác nhau:

  • Tất cả các điểm mã dưới 128 được mã hóa thành 0xxxxxxx.

  • Tất cả các điểm mã khác được mã hóa thành 11xxxxxx 10xxxxxx ... 10xxxxxx.

Điều này có nghĩa là mã hóa của mỗi ký tự Unicode chứa một 0xxxxxxxbyte đơn hoặc một 11xxxxxxbyte đơn và 1 đến 5 10xxxxxxbyte.

Bằng cách chia tất cả các byte của đầu vào cho 64 , chúng ta biến 0xxxxxxxthành 0 hoặc 1 , 11xxxxxxthành 310xxxxxxthành 2 .

Nếu chúng ta so sánh thương số với 2 - đẩy 1 cho 2 ; và 0 cho 0 , 13 - mỗi ký tự sẽ được chuyển thành 0 , theo sau là 1 đến 5 1 's.

Tất cả những gì còn lại là chia chuỗi kết quả tại các lần xuất hiện bằng 0 , đếm số 1 giữa các số 0 đó và thêm một chuỗi vào số tiền.

Làm thế nào nó hoạt động

{     }%          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($_)}

Lưu ý

OK, điều này sẽ hoạt động và thực hiện trong hầu hết các trường hợp thử nghiệm ngoại trừ trường hợp 𩸽nào đó được tính như 3,3trên máy của tôi. Nhân vật đó thậm chí còn hiển thị là 7 byte trên máy tính của tôi. Tôi nghi ngờ đây là do một số loại lỗi trong phiên bản Windows hoặc .NET mà tôi đang chạy cục bộ, vì @Mego không có vấn đề đó . ( Chỉnh sửa: @cat chỉ ra điều này là do BOM . Cảm ơn bạn đã giải quyết bí ẩn đó, @cat! )

Tuy nhiên, điều đó vẫn không giải thích cho tất cả các vấn đề. Tôi nghĩ rằng tôi biết một số vấn đề đến từ đâu, mặc dù. Bên trong .NET, tất cả các chuỗi được tạo thành từ các đơn vị mã UTF-16 (là loại System.Char). Với kiểu truyền hình rất lỏng lẻo mà PowerShell sử dụng, có rất nhiều chuyển đổi và chuyển đổi ngầm định giữa các loại trong nền. Có khả năng đây là một yếu tố góp phần vào hành vi mà chúng ta đang thấy - ví dụ, [system.text.encoding]::utf8.getchars([System.Text.UTF8Encoding]::UTF8.GetBytes('𩸽'))trả về hai dấu vết không thể in được, thay vì một ký tự.


Giải trình

Mã rất đơn giản. Lấy đầu vào $args[0]và chuyển nó thành một mảng char để chúng ta có thể lặp qua từng thành phần của chuỗi |%{...}. Mỗi lần lặp, chúng tôi sử dụng lệnh gọi .NET [System.Text.Encoding]::UTF8.GetByteCount()( System.được ngụ ý) để lấy số byte của ký tự hiện tại $_. Điều đó được đặt trên đường ống cho đầu ra sau này. Vì đó là một tập hợp các [int]trả về, nên việc truyền vào một mảng là ẩn.

Chạy thử

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

Đã chỉnh sửa để thêm Điều này không đúng với yêu cầu null-byte đã được thêm vào thử thách sau khi tôi đăng ban đầu, miễn là bạn lấy dữ liệu từ tệp văn bản và chuyển nó như sau:

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.Vâng, đó là vì Byte-Order Mark , đó là những gì bạn nhận được trên Windows với UTF-8. Nói với Notepad ++ để sử dụng UTF-8 without BOM(vì bạn phải luôn luôn tránh BOM , đặc biệt là tương thích với Unaho) và bạn sẽ thấy tệp có kích thước 4 byte, vì BOM là 3 và 4 + 3 = 7
mèo

@cat Ah, vâng, điều đó có ý nghĩa. OK, do đó chiếm sự khác biệt trong kích thước tập tin. Tuy nhiên, điều đó vẫn không giải thích cho hành vi khác nhau bên trong vỏ. Ví dụ: lưu nó dưới dạng UTF-8 mà không có BOM và chạy get-content -Encoding UTF8 .\z.txt|%{.\bytes-per-character.ps1 $_}vẫn trả về 3,3.
admBorkBork



6

JavaScript (ES6), 54 45 43 byte

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

Chỉnh sửa: Đã lưu 2 byte với sự trợ giúp từ @ l4m2.


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

@ l4m2 Điều đó không thành công đối với các ký tự không phải BMP nhưng tôi đã có thể sửa nó.
Neil


5

Perl 6 ,  77 69  63 byte

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 sử dụng các chuỗi NFG, tôi phải lấy các byte trực tiếp, điều này vượt qua tính năng này.
(NFG giống như NFC ngoại trừ nó cũng tạo ra các loại tiền mã hóa tổng hợp)

Đầu ra được phân tách bằng dòng mới.

Kiểm tra:

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)

Giải trình:

# 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

Điều này hoạt động vì byte đầu tiên trong một bộ mã nhiều byte có số byte được mã hóa bên trong nó và các byte khác trong bộ mã có tập bit cao nhất, nhưng không phải là cao nhất tiếp theo. Trong khi các điểm mã byte đơn không có tập bit cao nhất.


Không thể làm read:1và / hoặc /while$thay vào đó? Và nếu điều đó làm việc , if$?
Erik the Outgolfer

@ EʀɪᴋᴛʜᴇGᴏʟғᴇʀ Không vì điều đó sẽ được phân tích cú pháp như một cái gì đó khác nhau. Tôi có thể loại bỏ không gian trước whilemặc dù.
Brad Gilbert b2gills

Bạn có thể giải thích các biện pháp đối phó của NFG?
JDługosz

Nếu tôi lặp lại một byte NUL cho STDIN của chương trình này, nó sẽ in ra \n1\n1\n, đó có phải là chủ ý không? Về cơ bản, điều này có xử lý byte NUL không?
mèo

@cat Tại sao không? Khi tôi làm điều này: perl -e 'print "𩸽\0𩸽"' | perl6 -e '...'tôi nhận được 4␤1␤4như tôi mong đợi. (Phần về nuls đã được thêm vào sau khi tôi đăng)
Brad Gilbert b2gills

5

Python 3, 82 byte

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

Câu này dài hơn nhiều so với câu trả lời khác của Python và phần lớn các câu trả lời khác, nhưng sử dụng một cách tiếp cận liên quan đến logarit mà tôi chưa thấy.

Một hàm ẩn danh nhận đầu vào, thông qua đối số, dưới dạng chuỗi và trả về danh sách.

Hãy thử nó trên Ideone

Làm thế nào nó hoạt động

Phương pháp này dựa vào cách UTF-8 mã hóa điểm mã của một ký tự. Nếu điểm mã nhỏ hơn 128, ký tự được mã hóa như trong ASCII:

0xxxxxxx

trong đó xđại diện cho các bit của điểm mã. Tuy nhiên, đối với các điểm mã lớn hơn hoặc bằng 128, byte đầu tiên được đệm với cùng số 1s với tổng số byte và các byte tiếp theo bắt đầu 10. Các bit của điểm mã sau đó được nhập vào để đưa ra chuỗi đa bào ngắn nhất có thể và bất kỳ bit nào còn lại sẽ trở thành 0.

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

và kể từ đó trở đi.

Bây giờ có thể nhận thấy rằng với mỗi số byte n, giới hạn trên cho số bit điểm mã được đưa ra bởi (-n+7)+6(n-1) = 5n+1. Do đó, điểm mã giới hạn trên ccho mỗi điểm nđược đưa ra, theo số thập phân, theo c= 2^(5n+1). Sắp xếp lại này cho n = (log2(c)-1)/5. Vì vậy, đối với bất kỳ điểm mã nào, số byte có thể được tìm thấy bằng cách đánh giá biểu thức trên và sau đó lấy trần.

Tuy nhiên, điều này không hoạt động đối với các điểm mã trong phạm vi 64 <= c <= 127, vì việc thiếu phần đệm 1do mã hóa giống như ASCII cho các ký tự 1 byte có nghĩa là giới hạn trên sai được dự đoán và log2không được xác định c = 0, xảy ra nếu một byte rỗng có mặt trong đầu vào. Do đó, nếu c <= 127, một giá trị 1được trả về cho n.

Đây chính xác là những gì mã đang làm; đối với mỗi ký tự itrong chuỗi x, điểm mã được tìm thấy bằng cách sử dụng ordhàm và trần của biểu thức được tìm thấy bằng cách sử dụng số nguyên thay vì phân chia float bằng cách 5sau đó thêm 1. Do kiểu float của Python luôn đại diện cho các số nguyên x.0, ngay cả sau khi chia số nguyên, kết quả được truyền cho inthàm để loại bỏ dấu 0. Nếu ord(i) <= 127, ngắn mạch logic có nghĩa 1là thay vào đó được trả lại. Số lượng byte cho mỗi ký tự được lưu trữ dưới dạng một phần tử trong danh sách và danh sách này được trả về.


5

Java 10, 100 96 95 67 61 byte

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

-4 byte loại bỏ khoảng trắng bởi vì điều này được cho phép trong các bình luận
-1 byte thay đổi UTF-8thành utf8
-28 byte đi từ Java 7 đến 8 ( a->{...}thay vì void c(char[]i)throws Exception{...})
-3 byte lấy đầu vào là mảng Chuỗi thay vì mảng ký tự và
-3 byte đi từ Java 8 đến 10 ( varthay vì String)

Giải trình:

Hãy thử trực tuyến.

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

Nó hoạt động cho byte rỗng?
con mèo

@cat Trường hợp kiểm tra cho byte rỗng sau đó đã được thêm vào. Nhưng vâng, nó cũng hoạt động với null-byte và tôi đã thêm trường hợp thử nghiệm.
Kevin Cruijssen

3

Julia, 34 byte

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

Đây là một hàm ẩn danh chấp nhận một chuỗi và trả về một mảng số nguyên. Để gọi nó, gán nó cho một biến.

Cách tiếp cận khá đơn giản: Nếu đầu vào trống, đầu ra trống. Mặt khác, chúng ta ánh xạ sizeofhàm, tính số byte trong một chuỗi, cho mỗi chuỗi con một ký tự.

Hãy thử trực tuyến! (bao gồm tất cả các trường hợp thử nghiệm)


s->[sizeof("$c")for c=s]tiết kiệm một vài byte.
Dennis

Tiền lẻ; không split("","")không trở về []? (JavaScript là "".split("")có.)
Neil

@Neil split("","")dường như đưa ra ""(không giống như trong Python đưa ra một ngoại lệ) nhưng tôi không biết gì về khả năng tương thích []""trong julia.
mèo

@Neil Không, split("", "") == [""]tức là mảng một thành phần có chứa một chuỗi rỗng, nhưng vấn đề là điều sizeof("") == 0mà OP cho biết không được phép.
Alex A.

@Dennis Điều đó sẽ thất bại cho các chuỗi không thể lập chỉ mục. (Mặc dù không thể nghĩ ra một ví dụ trực tiếp.)
Alex A.

3

PHP, 92 57 byte

Về ý nghĩ thứ hai, bạn có thể làm điều này với ít khó khăn hơn nhiều:

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

Hãy thử lưu ý trực tuyến rằng nó dài hơn một chút vì nó sử dụng stdin chứ không phải là một đối số chương trình.
Phiên bản này yêu cầu bạn bỏ qua các thông báo gửi đến stderr nhưng không sao .

phiên bản cũ:
Sử dụng một cách tiếp cận khá khác với câu trả lời php khác. Dựa vào việc thiếu hỗ trợ riêng cho các chuỗi nhiều byte trong php.

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

Câu trả lời tốt đẹp! Tôi nghĩ bạn có thể bỏ hoàn toàn thẻ mở hoặc đổi nó thành<?=
mèo

Không có thẻ, đó là một đoạn mã chứ không phải là một chương trình, và ngay cả khi điều đó cho phép, nó khiến tôi cảm thấy mơ hồ bẩn thỉu. Với thẻ thay thế, bạn sẽ gặp lỗi phân tích cú pháp (hoặc ít nhất là tôi đã làm trên php 5.5, đây là những gì tôi đã sử dụng).
dùng55641

Được rồi :) Tôi không biết PHP (tôi cũng không muốn, ho ) nhưng tôi sẽ chỉ cho bạn ở đây: codegolf.stackexchange.com/questions/2913
mèo

3

Emacs Lisp, 55 49 byte

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

Đầu tiên phân tích chuỗi thành một danh sách các ký tự với (mapcar 'string s). Các stringchức năng trong Emacs Lisp có một danh sách các nhân vật và xây dựng một chuỗi ra khỏi chúng. Do cách Emacs phân tách các chuỗi với mapcar(nghĩa là thành một danh sách các số nguyên, không phải các ký tự hoặc chuỗi), nên việc chuyển đổi rõ ràng này là cần thiết. Sau đó ánh xạ string-byteshàm vào danh sách các chuỗi đó.

Thí dụ:

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

Testcase:

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

Câu trả lời cũ:

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

Ung dung:

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

Testcase:

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


Điều gì xảy ra nilnếu bạn làm phẳng kết quả?
Adám

1
@ Adám nillà một danh sách trống (và cách duy nhất để nói "sai" trong Emacs). Mặc dù không có tiêu chuẩn làm phẳng trong Emacs (bạn có thể sử dụng dấu gạch ngang -flatten), bất kỳ triển khai nào có thể sẽ loại bỏ nó.
Chúa Yuuma

3

JavaScript (Nút), 27 byte

s=>s.map(Buffer.byteLength)

Cái này lấy đầu vào là một mảng các ký tự riêng lẻ và trả về một mảng số byte.

Bufferlà một phương pháp biểu diễn dữ liệu nhị phân thô. Buffer.byteLpm (chuỗi) cho số byte trong chuỗi. UTF-8 là mã hóa mặc định. Lưu ý rằng chỉ có Node.js có bộ đệm, không phải trình duyệt JS. Tương đương trình duyệt thô được gọi là Blob , có 31 byte:

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

Kiểm tra

Lưu tệp này và chạy nó qua nút hoặc thử trực tuyến .

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

Đây sẽ là kết quả:

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

Chơi gôn

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

Thuật toán

chuỗi đầu vào hexdump, gấp 2 ký tự trên mỗi dòng, chỉ cắt char đầu tiên

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

2
c
b
e
8
a
f
a
b
b

(4 bit thứ tự cao của mỗi byte đầu vào dưới dạng hex hex, mỗi bit trên một dòng)

Xóa "byte tiếp tục" 0x80..0xBF

tr -d '89ab'

2
c

e


f

(những gì còn lại, là 4 bit của byte đầu tiên của mỗi char unicode)

ánh xạ các bit đầu tiên vào chiều dài char, thu gọn đầu ra và in

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

1 2 3 4

Kiểm tra

 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 Cách tiếp cận đẹp. Bạn thực sự đọc kết quả trực tiếp từ đầu vào.
Adám

Các -ttùy chọn để trlà quen thuộc với tôi, và rõ ràng là một phần mở rộng GNU. Đường ống để thay thế lệnh sau echocũng có thể có giá trị giải thích chi tiết hơn một chút.
tripleee


2

C #, 89 82 byte

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

Một lambda C # đơn giản lặp qua chuỗi và trả về danh sách được phân tách bằng dấu cách.

Chỉnh sửa: lưu 6 byte nhờ một số bình luận rất hay.


khá chắc chắn bạn có thể làmvar J="";...
mèo

Ngoài ra, OP tuyên bố trong một nhận xét rằng bạn không cần phải phân tách không gian đầu ra 11211 2 1 2cả hai đều ổn
mèo

1
@cat Cảm ơn, đã lưu cho tôi 6 byte
AstroDan

Ngoài ra, bạn có thêm một không gian trong} return J;};
mèo

Có vẻ như bạn cần using System.Texthoặc ở đó - nhập khẩu không miễn phí.
con mèo

2

Haskell, 85 byte

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

Hơi muộn một chút, nhưng điều này sẽ ngắn hơnmap$...
H.PWiz


1

C, 85 byte.

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

Kiểm tra 4 bit cao của mỗi byte để xác định mã hóa và số byte tiếp theo cần bỏ qua;


Điều này có hoạt động trên byte không?
mèo

Đúng, các while *c lối thoát trên một chuỗi rỗng và `c + = d 'bỏ qua các giá trị rỗng ở giữa một điểm mã nhiều byte.
HỎI

1
Điều đó không chính xác. Kết thúc của một chuỗi ( char*, thực sự) trong C được đánh dấu bằng một byte null. Không thể phân biệt byte rỗng với kết thúc thực tế của chuỗi.
Dennis

@Dennis Chính xác vì không có sự khác biệt :)
mèo

1
OP đã nêu trong một nhận xét (và bây giờ trong bài đăng) rằng bạn có thể yêu cầu độ dài của chuỗi theo byte làm đối số, do đó, điều đó sẽ có hiệu lực một lần nữa
cat

1

Yếu tố, 57 87 82 80 byte

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

Giải thích:

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

Bài kiểm tra đơn vị:

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

Tất cả đều vượt qua, bây giờ. c:


1

Swift 2.2, 67 52 50 byte

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

Thật xấu xí. Không có cách nào để có được độ dài UTF-8 của một nhân vật trong Swift, vì vậy tôi cần phải lặp qua chuỗi theo ký tự, chuyển đổi Characterthành a Stringvà tìm countký tự đơn đó String(ít nhất, có ít nhất là có tích hợp phương pháp để làm điều đó). Tìm kiếm tối ưu hóa, có thể sử dụng một máy quét.

Bản sửa đổi 1: Đã lưu 15 byte bằng cách sử dụng countthay vì underestimateCount().

Sửa đổi 2: Đã lưu 2 ký tự khác bằng cách sử dụng vòng lặp for-in thay vì cho mỗi lần đóng.


1

Rust, 53 byte

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

Rust có các nguyên thủy utf-8 char, iterators và lambdas, vì vậy điều này rất đơn giản. Mã kiểm tra:

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

Đầu ra

1211133112111114444 

1

jq, 26 ký tự

(Tùy chọn dòng lệnh 23 ký tự + 3 ký tự)

(./"")[]|utf8bytelength

Hy vọng cạnh tranh. Mặc dù utf8bytelengthđã được thêm 9 ++ tháng trước câu hỏi này, nhưng nó vẫn không được đưa vào phiên bản phát hành.

Chạy mẫu:

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 byte

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

Đầu vào là một mảng byte.

Số lượng byte trong một ký tự UTF-8 bằng với số 1bit dẫn đầu trong byte đầu tiên (trừ khi không có 1s, trong trường hợp đó là ký tự là 1 byte). Để tìm số lượng 1 hàng đầu, chương trình tìm đầu tiên 0trong biểu diễn nhị phân, sau đó thêm 1 nếu đây là 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 byte

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

Về mặt kỹ thuật, s là một chuỗi char, nhưng hóa ra có một chuyển đổi ngầm cho phép một chuỗi được truyền vào.

Khi kiểm tra điều này trong bảng điều khiển với !±≡𩸽, nó sẽ chia kanji thành hai ký tự, mỗi ký tự dài 3 byte. Tất cả các trường hợp thử nghiệm khác hoạt động tốt.

Chỉnh sửa: Hóa ra nhập không gian tên phổ biến không ẩn. Lên thêm 12 ký tự.


1) Câu trả lời về quyền hạn của Timmy D có cùng vấn đề 6 byte-per-kanji. Tôi cho rằng Windows bị câm và vô dụng với Unicode. 2) Nếu bạn nhận được 6 byte cho chữ Hán khi đọc từ một tệp được gắn với UTF-8 without BOMthì điều này là sai và cần được sửa. 3) Có vẻ như F # cần các câu lệnh muốn let f(x)= ...kết thúc ;;, như SML. 4) Bạn có thể bỏ qua việc gán tên hàm ẩn danh này, nghĩa là (s)=seq{for c in s->Encoding.UTF8.GetByteCount([|c|])}.
mèo

Ngoài ra, tôi nhận được error FS0039: The namespace or module 'Encoding' is not definedkhi cố gắng chạy này. Tôi đang làm gì sai?
mèo

Ngoài ra, chào mừng bạn đến với Câu đố lập trình và Code Golf, đây là câu trả lời đầu tiên hay! : D
mèo

@cat Bạn cần mở System.Textkhông gian tên. Tôi giả sử không gian tên mở và mã nhập được bao gồm, đến từ câu trả lời C # của AstroDan.
giao diện kín

Bạn cần phải đếm số byte của bất kỳ import, #include, open, load, require, using, USING:vv ở đây trên PPCG. Câu trả lời C # của AstroDan cũng tương tự sai, và tôi đã thông báo cho họ về điều đó.
mèo

1

05AB1E , 15 byte

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

Hãy thử trực tuyến.
Tiêu đềεđược sử dụng để for-every trên tất cả các trường hợp thử nghiệm;
Footerï]J]»để in đẹp các danh sách ký tự đầu ra (ï: số thập phân và ký tự cho số nguyên ;]: close if-other và for-every ;J: Nối các chữ số với nhau ;}: đóng tiêu đề foreach ;»: Nối theo dòng mới).

Giải trình:

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

Vì 05AB1E không có bất kỳ nội trang nào để chuyển đổi ký tự thành số byte được sử dụng, tôi sử dụng Çđể chuyển đổi các ký tự thành giá trị unicode của chúng và trong mỗi for thực hiện các thao tác sau trong mã giả:

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

Lấy cảm hứng từ câu trả lời Python 3 của @TheBikingViking .


0

Zsh , 41 byte

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

Hãy thử trực tuyến!

Zsh nhận biết UTF-8, vì vậy chúng tôi chia chuỗi trên các ký tự, sau đó vô hiệu hóa đa chuỗi và in độ dài của mỗi ký tự.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.