use comfy_table for output

This commit is contained in:
mehbark 2026-04-22 18:11:30 -04:00
parent 3cf5b5e652
commit b862767944
Signed by: mbk
GPG key ID: E333EC1335FFCCDB
3 changed files with 244 additions and 27 deletions

201
Cargo.lock generated
View file

@ -2,6 +2,207 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "bitflags"
version = "2.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3"
[[package]]
name = "cfg-if"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
[[package]]
name = "comfy-table"
version = "7.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "958c5d6ecf1f214b4c2bbbbf6ab9523a864bd136dcf71a7e8904799acfe1ad47"
dependencies = [
"crossterm",
"unicode-segmentation",
"unicode-width",
]
[[package]]
name = "crossterm"
version = "0.29.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b"
dependencies = [
"bitflags",
"crossterm_winapi",
"document-features",
"parking_lot",
"rustix",
"winapi",
]
[[package]]
name = "crossterm_winapi"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acdd7c62a3665c7f6830a51635d9ac9b23ed385797f70a83bb8bafe9c572ab2b"
dependencies = [
"winapi",
]
[[package]]
name = "document-features"
version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61"
dependencies = [
"litrs",
]
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "libc"
version = "0.2.185"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f"
[[package]]
name = "linux-raw-sys"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "litrs"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092"
[[package]]
name = "lock_api"
version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965"
dependencies = [
"scopeguard",
]
[[package]]
name = "parking_lot"
version = "0.12.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a"
dependencies = [
"lock_api",
"parking_lot_core",
]
[[package]]
name = "parking_lot_core"
version = "0.9.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1"
dependencies = [
"cfg-if",
"libc",
"redox_syscall",
"smallvec",
"windows-link",
]
[[package]]
name = "redox_syscall"
version = "0.5.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d"
dependencies = [
"bitflags",
]
[[package]]
name = "rustix"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
[[package]]
name = "substitution-helper"
version = "0.1.0"
dependencies = [
"comfy-table",
]
[[package]]
name = "unicode-segmentation"
version = "1.13.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c"
[[package]]
name = "unicode-width"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254"
[[package]]
name = "winapi"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
dependencies = [
"winapi-i686-pc-windows-gnu",
"winapi-x86_64-pc-windows-gnu",
]
[[package]]
name = "winapi-i686-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
[[package]]
name = "winapi-x86_64-pc-windows-gnu"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-link"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5"
[[package]]
name = "windows-sys"
version = "0.61.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc"
dependencies = [
"windows-link",
]

View file

@ -4,3 +4,4 @@ version = "0.1.0"
edition = "2024"
[dependencies]
comfy-table = "7.2.2"

View file

@ -5,6 +5,8 @@ use std::{
process,
};
use comfy_table::{CellAlignment, ContentArrangement, Table, presets::UTF8_FULL};
fn main() {
let mut subst = HashMap::new();
for pair in env::args().skip(1) {
@ -26,9 +28,7 @@ fn main() {
.or_default() += 1;
}
println!("Letters:");
print_freqs(byte_frequencies, &subst);
println!();
print_freqs(byte_frequencies, &subst, "L");
let mut digram_freqs: HashMap<[char; 2], usize> = HashMap::new();
for slice in inp.as_bytes().windows(2) {
@ -41,9 +41,7 @@ fn main() {
*digram_freqs.entry([*a as char, *b as char]).or_default() += 1;
}
println!("Digrams:");
print_freqs(digram_freqs, &subst);
println!();
print_freqs(digram_freqs, &subst, "Di");
let mut trigram_freqs: HashMap<[char; 3], usize> = HashMap::new();
for slice in inp.as_bytes().windows(3) {
@ -58,9 +56,7 @@ fn main() {
.or_default() += 1;
}
println!("Trigrams:");
print_freqs(trigram_freqs, &subst);
println!();
print_freqs(trigram_freqs, &subst, "Tri");
for byte in inp.bytes() {
let new_byte = subst
@ -72,7 +68,11 @@ fn main() {
}
}
fn print_freqs<const N: usize>(freqs: HashMap<[char; N], usize>, subst: &HashMap<u8, u8>) {
fn print_freqs<const N: usize>(
freqs: HashMap<[char; N], usize>,
subst: &HashMap<u8, u8>,
gram_name: &'static str,
) {
let total_freqs: usize = freqs.values().sum();
let mut freqs: Vec<_> = freqs
@ -81,23 +81,38 @@ fn print_freqs<const N: usize>(freqs: HashMap<[char; N], usize>, subst: &HashMap
.collect();
freqs.sort_by_key(|(f, count)| (*count, *f));
for (c, count) in freqs.iter().rev() {
println!(
"{:>3}: {:4.1}% ({count:4})",
c.iter()
.map(|c| {
let Ok(b): Result<u8, _> = (*c).try_into() else {
panic!()
};
let mut table = Table::new();
if let Some(new) = subst.get(&b) {
(*new as char).to_ascii_uppercase()
} else {
(b as char).to_ascii_lowercase()
}
})
.collect::<String>(),
(*count as f32 / total_freqs as f32) * 100.
);
table
.load_preset(UTF8_FULL)
.apply_modifier(comfy_table::modifiers::UTF8_SOLID_INNER_BORDERS)
.set_content_arrangement(ContentArrangement::Dynamic)
.set_header([gram_name, "Freq", "N"]);
for column in table.column_iter_mut() {
column.set_cell_alignment(CellAlignment::Right);
}
for (c, count) in freqs.iter().rev() {
let char = c
.iter()
.map(|c| {
let Ok(b): Result<u8, _> = (*c).try_into() else {
panic!()
};
if let Some(new) = subst.get(&b) {
(*new as char).to_ascii_uppercase()
} else {
(b as char).to_ascii_lowercase()
}
})
.collect::<String>();
let proportion = (*count as f32 / total_freqs as f32) * 100.;
table.add_row([char, format!("{proportion:.1}%"), format!("{count}")]);
}
println!("{table}");
}