sắp xếp theo giá trị hex


14

Sử dụng coreutils sort, làm cách nào tôi có thể sắp xếp số theo giá trị thập lục phân (trường)? Tôi đã mong đợi một cái gì đó dọc theo dòng

sort -k3,3x file_to_sort

tuy nhiên, như vậy xkhông tồn tại.

Chỉnh sửa: Giải pháp tốt nhất tôi nghĩ ra cho đến nay là:

{ echo ibase=16; cut -d' ' -f3 file_to_sort; } |
  bc | paste -d: - file_to_sort | sort -t: -k1,1n | cut -d: -f2-

trong đó cách ly cut -d' ' -f3trường tìm kiếm (tất nhiên là -k3,3- điều này có thể thay đổi) và bcchuyển đổi thành số thập phân (yêu cầu hex chữ hoa, không có 0xtiền tố, khớp với trường hợp của tôi). Sau đó, tôi tham gia, sắp xếp và chia cột.


-k3,3? Bạn có hex nubers nhìn chằm chằm với 0x và tất cả cùng chiều dài? Không kết hợp chữ hoa / chữ thường? Nếu có, họ nên sắp xếp đúng khi được hiểu là chuỗi. Có lẽ bạn có thể cho chúng tôi thấy một số dữ liệu ví dụ?

@yeti: Thật không may, không.
stefan

Câu trả lời:


5

Một giải pháp trong perl:

$ perl -anle '
    push @h, [$F[-1],$_];
    END {
        print for map  { $_->[0] }
                  sort { $a->[1] <=> $b->[1] }
                  map  { [$_->[1],hex($_->[0])] } @h;
    }
' file
4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

Giải trình

  • Trong khi xử lý tệp, chúng ta tạo một mảng của mảng @h, mỗi phần tử của nó là một tham chiếu mảng [$F[-1],$_], với phần tử đầu tiên là giá trị hex để so sánh và phần tử thứ hai là toàn bộ dòng.

  • Trong ENDkhối, chúng tôi sử dụng biến đổi Schwartzian :

    • Với mỗi phần tử của @h, tạo một mảng ẩn danh, chứa toàn bộ dòng ( $_->[1]phần tử thứ hai của mỗi mảng ref in @h) và giá trị hex để so sánhhex($_->[0])]

    • Sắp xếp trên cơ sở mảng trên giá trị hex $a->[1] <=> $b->[1]

    • Lấy phần tử đầu tiên của mỗi mảng ref trong mảng được sắp xếp map { $_->[0] } sau đó in kết quả.

Cập nhật

Với đề xuất của @Joseph R, không sử dụng Schwartzian Transform:

$ perl -anle '
    push @h, [hex($F[-1]),$_];
    END {
        print $_->[1] for
            sort { $a->[0] <=> $b->[0] } @h;
    }
' file

Cập nhật 2

Sau khi đọc bình luận của stefan, tôi nghĩ rằng điều này có thể gọi direct:

$ perl -e '
    print sort {hex((split(/\s+/,$a))[-1]) <=> hex((split(/\s+/,$b))[-1])} <>;
' file
4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

+1 nhưng tại sao không chỉ : print for sort { hex $a->[-1] <=> hex $b->[-1] } @h? Các hexnhà điều hành hầu như không đủ đắt để bảo đảm một Schwartzian, phải không?
Joseph R.

@JosephR.: Có thể, nhưng một Schwartzian linh hoạt hơn và làm việc trong mọi trường hợp. Tôi nghĩ rằng chúng ta có thể có một giải pháp khác bằng cách tính giá trị hex trong khi xử lý, sẽ cập nhật câu trả lời của tôi sớm.
cuonglm

Dung dịch mát. Không biết mẫu này có một cái tên: trang trí-sắp xếp-không trang trí. Xem bình luận của tôi ở trên.
stefan

@stefan: xem câu trả lời cập nhật của tôi.
cuonglm

@Gnouc: có, Bản cập nhật thứ 2 của bạn chắc chắn đủ điều kiện là wrt trực tiếp. trí tưởng tượng ban đầu của tôi.
stefan

6

Tôi sử dụng dữ liệu ví dụ này:

1 hdh d12
2 ukr 9f
3 ezh ae
4 jjk 7
5 hhf 25

Ý tưởng là tạo ra một phiên bản mới của dữ liệu này với trường sắp xếp ở dạng thập phân. Tức là awkchuyển đổi nó, đưa nó vào từng dòng, kết quả được sắp xếp và như bước cuối cùng, trường được thêm vào sẽ bị xóa:

awk '{val="0x" $3; sub("^0x0x","0x",val); print strtonum(val),$0 ;}' file | 
  sort -n | 
  sed 's/^[^ ]* //'

Kết quả nào cho kết quả này:

4 jjk 7
5 hhf 25
2 ukr 9f
3 ezh ae
1 hdh d12

1
Cảm ơn, giải pháp khá tuyệt. Xin lỗi vì tôi đã không đăng bản chỉnh sửa của mình trước đó, nó tuân theo cách tiếp cận tương tự bằng cách sử dụng cut + paste. Tôi đã hy vọng cho một giải pháp trực tiếp hơn mặc dù ...
stefan

@stefan Cái gì được coi là "trực tiếp"? Có giải pháp phải sử dụng sort?
Joseph R.

@Joseph, Cái gì được coi là "trực tiếp"? Rằng là câu hỏi đúng. Về cơ bản, tất cả các giải pháp cho đến nay (của Hauke, Gnouc bên dưới và của tôi) đều làm một cái gì đó tương tự: Giải mã giá trị hex, đính kèm kết quả vào các dòng, sắp xếp theo nó và loại bỏ nó. Tôi đang tìm kiếm một cái gì đó không sử dụng mô hình trang trí sắp xếp-không trang trí . Cả hai giải pháp đều vượt trội so với tôi, trong đó tey hoạt động trong một đường ống dẫn. Tôi đã chọn cái này vì cá nhân tôi thích sử dụng awk (cái búa nhỏ hơn) so với Perl cho loại nhiệm vụ này.
stefan

Tôi đã chuyển lựa chọn của mình về câu trả lời xuống số 3 bên dưới, vì bản cập nhật thứ hai của Gnouc.
stefan

1

Đầu vào

$ cat /tmp/input
0x45 aaa 333
0x50 dd 33
0x4 bbbb 444
0x456 cc 22
0x5 eee 1111

Sắp xếp một lớp lót

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1 | cut -f2- -d' '
0x4 bbbb 444
0x5 eee 1111
0x45 aaa 333
0x50 dd 33
0x456 cc 22

Sắp xếp từng bước

Bước 1: Thêm một cột đầu tiên mới với biểu diễn thập phân của số hex.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input 
69 0x45 aaa 333
80 0x50 dd 33
4 0x4 bbbb 444
1110 0x456 cc 22
5 0x5 eee 1111

Bước 2: Sắp xếp các dòng số trên trường đầu tiên.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1
4 0x4 bbbb 444
5 0x5 eee 1111
69 0x45 aaa 333
80 0x50 dd 33
1110 0x456 cc 22

Bước 3: Xóa cột đầu tiên.

$ gawk  --non-decimal-data '{ dec = sprintf("%d", $1); print dec " "  $0 }' /tmp/input | sort -n -k 1 | cut -f2- -d' '
0x4 bbbb 444
0x5 eee 1111
0x45 aaa 333
0x50 dd 33
0x456 cc 22

0

được điều chỉnh từ: http://www.unix.com/302536135-post6.html?s=b4b6b3ed50b6831717f6429113302ad6

: file-to-sort:

6F993B
954B29
A23F2F
BFA91D
C68C15
8F322F
5A6D40
6D512C
9D9D63
B4B823
A0641C
A79716
A18518

Chỉ huy:

awk '{printf("%050s\t%s\n", toupper($0), $0)}' file-to-sort | LC_COLLATE=C sort -k1,1 | cut -f2

Đầu ra:

C68C15
BFA91D
B4B823
A79716
A23F2F
A18518
A0641C
9D9D63
954B29
8F322F
6F993B
6D512C
5A6D40

- ở đâu các chữ cái viết thường ($ 0) "nâng cấp" chữ thường để chúng sắp xếp trước (không chắc là cần thiết chứ?)

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.