Không thể sử dụng `cut -c` (` --char character`) với UTF-8?


15

Lệnh cutcó một tùy chọn -cđể làm việc trên các ký tự, thay vì byte với tùy chọn -b. Nhưng điều đó dường như không hoạt động, tại en_US.UTF-8địa phương:

Byte thứ hai cho ký tự ASCII thứ hai (được mã hóa giống như trong UTF-8):

$ printf 'ABC' | cut -b 2          
B

nhưng không đưa ra lần thứ hai trong ba ký tự không phải ASCII của Hy Lạp trong ngôn ngữ UTF-8:

$ printf 'αβγ' | cut -b 2         
�

Không sao đâu - đó là byte thứ hai .
Vì vậy, chúng tôi nhìn vào nhân vật thứ hai thay thế:

$ printf 'αβγ' | cut -c 2 
�

Điều đó có vẻ bị hỏng.
Với một số thử nghiệm, hóa ra phạm vi 3-4hiển thị ký tự thứ hai:

$ printf 'αβγ' | cut -c 3-4
β

Nhưng điều đó cũng giống như các byte 3 đến 4:

$ printf 'αβγ' | cut -b 3-4
β

Nên -c không nhiều hơn -bUTF-8.

Tôi hy vọng thiết lập ngôn ngữ không phù hợp với UTF-8, nhưng so sánh, wchoạt động như mong đợi;
Nó thường được sử dụng để đếm byte, với tùy chọn -c( --bytes). (Lưu ý các tên tùy chọn khó hiểu.)

$ printf 'αβγ' | wc -c
6

Nhưng nó cũng có thể đếm các ký tự với tùy chọn -m( --chars), chỉ hoạt động:

$ printf 'αβγ' | wc -m
3

Vì vậy, cấu hình của tôi có vẻ ổn - nhưng có gì đó đặc biệt cut.

Có lẽ nó không hỗ trợ UTF-8 chút nào? Nhưng nó dường như hỗ trợ các ký tự nhiều byte, nếu không, nó sẽ không cần hỗ trợ -b-c.

Vì vậy những gì là sai? Và tại sao?


Thiết lập ngôn ngữ có vẻ phù hợp với utf8, theo như tôi có thể nói:

$ locale
LANG=en_US.UTF-8
LANGUAGE=en_US
LC_CTYPE=en_US.UTF-8
LC_NUMERIC="en_US.UTF-8"
LC_TIME="en_US.UTF-8"
LC_COLLATE="en_US.UTF-8"
LC_MONETARY="en_US.UTF-8"
LC_MESSAGES="en_US.UTF-8"
LC_PAPER="en_US.UTF-8"
LC_NAME="en_US.UTF-8"
LC_ADDRESS="en_US.UTF-8"
LC_TELEPHONE="en_US.UTF-8"
LC_MEASUREMENT="en_US.UTF-8"
LC_IDENTIFICATION="en_US.UTF-8"
LC_ALL=

Đầu vào, byte theo byte:

$ printf 'αβγ' | hd 
00000000  ce b1 ce b2 ce b3                                 |......|
00000006

Hấp dẫn! Có vẻ như -clà sử dụng cùng một mã như -b. Bạn đã xem mã nguồn chưa? Có lẽ bạn có thể tìm thấy một gợi ý những gì -cthực sự có nghĩa là cho.
michas

Câu trả lời:


13

Bạn chưa nói cutbạn đang sử dụng cái gì, nhưng vì bạn đã đề cập đến tùy chọn dài GNU --characterstôi sẽ cho rằng đó là tùy chọn . Trong trường hợp đó, lưu ý đoạn văninfo coreutils 'cut invocation' này từ :

‘-c character-list’
‘--characters=character-list’

Chọn để chỉ in các ký tự ở các vị trí được liệt kê trong danh sách ký tự. Giống như -bbây giờ , nhưng quốc tế hóa sẽ thay đổi điều đó.

(nhấn mạnh thêm)

Hiện tại, GNU cutluôn hoạt động theo các "ký tự" byte đơn, do đó, hành vi bạn thấy được mong đợi.


Hỗ trợ cả hai -b-ccác tùy chọn được POSIX yêu cầu - chúng không được thêm vào GNU cutvì nó có hỗ trợ nhiều byte và chúng hoạt động đúng, nhưng để tránh gây ra lỗi trên đầu vào tuân thủ POSIX. Điều tương tự cũng -cđã được thực hiện trong một số cuttriển khai khác , mặc dù không phải là FreeBSDOS X ' s ít nhất.

Đây là hành vi lịch sử của -c. -bđã được thêm mới để đảm nhận vai trò byte để -ccó thể hoạt động với các ký tự nhiều byte. Có thể trong một vài năm, nó sẽ hoạt động như mong muốn, mặc dù tiến độ chưa thực sự nhanh chóng (đã hơn một thập kỷ rồi). GNU cut thậm chí còn không thực hiện -ntùy chọn này , mặc dù nó là trực giao và nhằm giúp chuyển đổi. Có những vấn đề tương thích tiềm ẩn với các tập lệnh cũ, có thể là một mối quan tâm, mặc dù tôi không biết rõ ràng lý do là gì.


1
làm tốt lắm. bạn cũng sẽ tìm thấy cùng một loại nhận xét trong trtài liệu của GNU . và thậm chí tartrừ khi tôi sai. Tôi đoán đó là một dự án lớn.
mikeerv

Có cách giải quyết nào cho việc thăm dò unicode cutkhông? Ví dụ, nơi có thể tải xuống các nguồn để vá cut? Hoặc nó sẽ dễ dàng hơn để sử dụng một tiện ích khác? ( grepgiải pháp bên dưới không hoạt động trơn tru với các phạm vi, ví dụ 5-8,44-49)
dma_k

xem bài viết năm 2017 này, có tiêu đề phụ Ghi chú ngẫu nhiên và các con trỏ liên quan đến nỗ lực đang diễn ra để thêm hỗ trợ đa nhân và unicode trong GNU Coreutils Hồi
myrdd 12/12/18

bạn có thể tìm thấy một số lựa chọn thay thế cut -ctại đây: superuser.com/questions/506164/iêng
myrdd 12/12/18

5

colrm(một phần của util-linux, nên đã được cài đặt trên hầu hết các bản phân phối) dường như xử lý quốc tế hóa tốt hơn nhiều:

$ echo 'αβγ' | colrm 3
αβ
$ echo 'αβγ' | colrm 2
α

Cảnh giác với việc đánh số: colrm Nsẽ xóa các cột khỏi N, in các ký tự lên đến N-1.

( tín dụng )


2

Vì nhiều greptriển khai là nhận biết đa bào, bạn cũng có thể sử dụng grep -ođể mô phỏng một số cách sử dụng cut -c.

$ echo Τηεοδ29 | grep -o '^..'
Τη
$ echo Τηεοδ29 | egrep -o '^..' | grep -o '.$'
η

Điều chỉnh số lượng thời gian để mô phỏng cutphạm vi.

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.