วิธีรวบรวมสถิติการเกิดไบต์ในไฟล์ไบนารี?


12

ฉันต้องการทราบสิ่งที่เทียบเท่า

cat inputfile | sed 's/\(.\)/\1\n/g' | sort | uniq -c

นำเสนอใน/programming/4174113/how-to-gather-characters-usage-statistics-in-text-file-using-unix- คำสั่งสำหรับการผลิตสถิติการใช้อักขระในไฟล์ข้อความสำหรับไบนารีไฟล์นับ ไบต์ง่าย ๆ แทนตัวละครเช่นเอาท์พุทควรอยู่ในรูปแบบของ

18383 57
12543 44
11555 127
 8393 0

ไม่สำคัญว่าคำสั่งจะใช้เวลานานเท่าใดเมื่ออ้างอิงกับอักขระ

หากฉันใช้คำสั่งสำหรับตัวละครกับไฟล์ไบนารีเอาต์พุตจะมีสถิติสำหรับลำดับที่ยาวของอักขระที่ไม่สามารถพิมพ์ได้ (โดยที่ฉันไม่ต้องการคำอธิบาย)

คำตอบ:


8

ด้วย GNU od:

od -vtu1 -An -w1 my.file | sort -n | uniq -c

หรือมีประสิทธิภาพมากขึ้นด้วยperl(ยังส่งออกจำนวน (0) สำหรับไบต์ที่ไม่เกิดขึ้น):

perl -ne 'BEGIN{$/ = \4096};
          $c[$_]++ for unpack("C*");
          END{for ($i=0;$i<256;$i++) {
              printf "%3d: %d\n", $i, $c[$i]}}' my.file

เพื่อให้ได้ตัวเลขในแถวแรกได้รับการยอมรับอย่างถูกต้องฉันต้องเพิ่ม| sort -nและ| sort -n -rเรียงลำดับจากมากไปน้อยตามลำดับ (การเรียงลำดับไม่ใช่ส่วนหนึ่งของคำถาม) เรียงลำดับอาจจะทำได้ดีกว่า ...
คาร์ลริกเตอร์

ดูเหมือนว่า overkill เล็กน้อยต้องเรียงลำดับไฟล์ทั้งหมด แต่ใช้งานได้สำหรับฉัน
Michael Anderson

จุดดี @Karl แม้ว่าจะไม่ได้รับการร้องขอการใช้sort -nที่นี่ทำให้รู้สึกมากขึ้น อัปเดตคำตอบแล้ว
Stéphane Chazelas

4

สำหรับไฟล์ขนาดใหญ่ที่ใช้การเรียงลำดับจะช้า ฉันเขียนโปรแกรม C สั้น ๆ เพื่อแก้ปัญหาเทียบเท่า ( ดูส่วนสำคัญนี้สำหรับ Makefile พร้อมการทดสอบ ):

#include <stdio.h>

#define BUFFERLEN 4096

int main(){
    // This program reads standard input and calculate frequencies of different
    // bytes and present the frequences for each byte value upon exit.
    //
    // Example:
    //
    //     $ echo "Hello world" | ./a.out
    //
    // Copyright (c) 2015 Björn Dahlgren
    // Open source: MIT License

    long long tot = 0; // long long guaranteed to be 64 bits i.e. 16 exabyte
    long long n[256]; // One byte == 8 bits => 256 unique bytes

    const int bufferlen = BUFFERLEN;
    char buffer[BUFFERLEN];
    int i;
    size_t nread;

    for (i=0; i<256; ++i)
        n[i] = 0;

    do {
        nread = fread(buffer, 1, bufferlen, stdin);
        for (i = 0; i < nread; ++i)
            ++n[(unsigned char)buffer[i]];
        tot += nread;
    } while (nread == bufferlen);
    // here you may want to inspect ferror of feof

    for (i=0; i<256; ++i){
        printf("%d ", i);
        printf("%f\n", n[i]/(float)tot);
    }
    return 0;
}

การใช้งาน:

gcc main.c
cat my.file | ./a.out

คุณมีแบบทดสอบหรือไม่? ไม่มีความคิดเห็นในรหัส โดยทั่วไปแล้วไม่ใช่ความคิดที่ดีที่จะใช้ไม่ได้ทดสอบและเผยแพร่โค้ดที่ยังไม่ได้ทดสอบหรือไม่ใส่คอมเม้นต์ - ไม่สำคัญว่าเป็นวิธีปฏิบัติทั่วไป ความเป็นไปได้ในการตรวจสอบการแก้ไขนั้นมี จำกัด ในแพลตฟอร์มนี้พิจารณาแพลตฟอร์มการโฮสต์โค้ดอย่างชัดเจน
Karl Richter

การทดสอบ @KarlRichter เป็นความคิดที่ดีที่จะเพิ่ม ฉันพบเวอร์ชันเก่าสำลักตัวอักษร '\ 0' รุ่นนี้ควรใช้งานได้ (ผ่านการทดสอบขั้นพื้นฐานบางอย่างเป็นอย่างน้อย)
Bjoern Dahlgren

fgetsรับบรรทัดไม่ใช่บัฟเฟอร์เต็ม คุณกำลังสแกนบัฟเฟอร์แบบเต็ม 4096 ไบต์สำหรับแต่ละบรรทัดที่อ่านจาก stdin คุณต้องอยู่ที่นี่ไม่ได้fread fgets
Stéphane Chazelas

@ StéphaneChazelas great - ไม่รู้ของ fread (ไม่ค่อยทำ I / O จาก C) อัปเดตตัวอย่างเพื่อใช้ fread แทน
Bjoern Dahlgren

ฉันได้เพิ่มifบล็อกล้อมรอบคำสั่ง printf ซึ่งทำให้เอาต์พุตอ่านได้ง่ายขึ้นถ้าบางไบต์ไม่เกิดขึ้นในไฟล์อินพุต: gist.github.com/martinvonwittich/ …
Martin von Wittich

3

ตามความหมาย sigma และ CV มักมีความสำคัญเมื่อตัดสินข้อมูลสถิติของเนื้อหาของไฟล์ไบนารีฉันได้สร้างโปรแกรม cmdline ที่ทำกราฟข้อมูลทั้งหมดนี้เป็นวงกลม ascii ของการเบี่ยงเบนไบต์จาก sigma
http://wp.me/p2FmmK-96
มันสามารถใช้กับ grep, xargs และเครื่องมืออื่น ๆ เพื่อแยกสถิติ ป้อนคำอธิบายรูปภาพที่นี่


1

recodeโปรแกรมสามารถทำเช่นนี้ได้อย่างรวดเร็วแม้สำหรับไฟล์ขนาดใหญ่ทั้งสถิติความถี่ทั้งไบต์หรือตัวละครในชุดตัวอักษรต่างๆ เช่นเพื่อนับความถี่ไบต์:

$ echo hello there > /tmp/q
$ recode latin1/..count-characters < /tmp/q
1  000A LF   1  0020 SP   3  0065 e    2  0068 h    2  006C l    1  006F o
1  0072 r    1  0074 t

ข้อควรระวัง - ระบุไฟล์ของคุณให้บันทึกเป็นอินพุตมาตรฐานไม่เช่นนั้นไฟล์จะถูกแทนที่ด้วยความถี่อักขระอย่างเงียบ ๆ !

ใช้recode utf-8/..count-characters < fileเพื่อถือว่าไฟล์อินพุตเป็น utf-8 มีชุดอักขระอื่น ๆ มากมายและจะล้มเหลวหากไฟล์มีอักขระผิดกฎหมาย


1

นี่คล้ายกับodคำตอบของ Stephane แต่จะแสดงค่า ASCII ของไบต์ มันยังเรียงตามความถี่ / จำนวนครั้งที่เกิดขึ้น

xxd -c1 my.file|cut -c10-|sort|uniq -c|sort -nr

ฉันไม่คิดว่ามันจะมีประสิทธิภาพตั้งแต่กระบวนการหลายอย่างเริ่มต้น แต่มันก็ดีสำหรับไฟล์เดียวโดยเฉพาะไฟล์ขนาดเล็ก

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.