168 lines
4.8 KiB
Rust
168 lines
4.8 KiB
Rust
use std::fs::File;
|
|
use std::io::{self, BufRead, Write};
|
|
use std::path::Path;
|
|
|
|
fn main() {
|
|
let mut run: bool = true;
|
|
let mut file_name: String = String::new();
|
|
let mut col_amount: i8 = 50;
|
|
|
|
while run {
|
|
print!("\x1b[2J\x1b[H");
|
|
println!("========== Justify some text ==========");
|
|
println!(" A) Set file name (Name: {})", file_name);
|
|
println!(
|
|
" B) Set column amount between 50 and 120 (Amount: {})",
|
|
col_amount
|
|
);
|
|
println!(" C) Justify and print text");
|
|
println!(" D) Justify and save text");
|
|
println!(" Quit (any other key)");
|
|
|
|
let mut choice: String = String::new();
|
|
print!("Your choice: ");
|
|
let _ = io::stdout().flush();
|
|
io::stdin()
|
|
.read_line(&mut choice)
|
|
.expect("Failed to read from stdin");
|
|
choice = choice.trim().to_ascii_lowercase().to_string();
|
|
|
|
match choice.as_str() {
|
|
"a" => {
|
|
file_name = set_file_name();
|
|
}
|
|
"b" => {
|
|
col_amount = set_col_amount();
|
|
}
|
|
"c" => {
|
|
print_justified_text(&file_name, col_amount);
|
|
}
|
|
"d" => {
|
|
save_justified_text(&file_name, col_amount);
|
|
}
|
|
_ => {
|
|
run = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn set_file_name() -> String {
|
|
let mut path_iscorrect: bool = false;
|
|
let mut path: String = String::new();
|
|
|
|
while !path_iscorrect {
|
|
path = String::new();
|
|
print!("Enter the desired file's path: ");
|
|
let _ = io::stdout().flush();
|
|
io::stdin()
|
|
.read_line(&mut path)
|
|
.expect("Failed to read from stdin");
|
|
path = path.trim().to_string();
|
|
|
|
path_iscorrect = Path::new(&path).exists();
|
|
if !path_iscorrect {
|
|
println!("The specified file does not exist. Please try again.");
|
|
}
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
fn set_col_amount() -> i8 {
|
|
let mut input_text: String;
|
|
let mut col_amount: i8 = 0;
|
|
let mut amount_iscorrect: bool = false;
|
|
|
|
while !amount_iscorrect {
|
|
input_text = String::new();
|
|
print!("Enter the desired column amount: ");
|
|
let _ = io::stdout().flush();
|
|
io::stdin()
|
|
.read_line(&mut input_text)
|
|
.expect("failed to read from stdin");
|
|
|
|
match input_text.trim().parse::<i8>() {
|
|
Ok(i) => {
|
|
col_amount = i;
|
|
amount_iscorrect = col_amount >= 50 && col_amount <= 120;
|
|
if !amount_iscorrect {
|
|
println!("The specified amount was not between 50 and 120. Please try again.");
|
|
}
|
|
}
|
|
Err(..) => println!(
|
|
"input is not an integer: {}. Please try again.",
|
|
input_text.trim()
|
|
),
|
|
};
|
|
}
|
|
|
|
return col_amount;
|
|
}
|
|
|
|
fn print_justified_text(filename: &str, col_amount: i8) {
|
|
if let Ok(lines) = read_lines(filename) {
|
|
for line in lines.flatten() {
|
|
let justified_text = justify_text(&line, col_amount);
|
|
println!("{}", justified_text);
|
|
}
|
|
} else {
|
|
println!("Failed to read the file.");
|
|
}
|
|
}
|
|
|
|
fn save_justified_text(filename: &str, col_amount: i8) {
|
|
let output_file = "output.txt";
|
|
let mut file = File::create(output_file).expect("Failed to create output file.");
|
|
|
|
if let Ok(lines) = read_lines(filename) {
|
|
for line in lines.flatten() {
|
|
let justified_text = justify_text(&line, col_amount);
|
|
writeln!(file, "{}", justified_text).expect("Failed to write to output file.");
|
|
}
|
|
println!("Written to {}", output_file);
|
|
}
|
|
}
|
|
|
|
fn justify_text(text: &str, col_amount: i8) -> String {
|
|
if text.len() >= col_amount as usize {
|
|
return text.to_string();
|
|
}
|
|
if text == "" {
|
|
return text.to_string();
|
|
}
|
|
|
|
let words: Vec<&str> = text.split_whitespace().collect();
|
|
|
|
if words.len() == 1 {
|
|
return format!("{:<width$}", words[0], width = col_amount as usize);
|
|
}
|
|
|
|
let mut justified = String::new();
|
|
let words_len: usize = words.iter().map(|word| word.len()).sum();
|
|
let total_spaces = (col_amount as usize) - words_len;
|
|
let gaps = words.len() - 1;
|
|
let spaces_per_gap = total_spaces / gaps;
|
|
let extra_spaces = total_spaces % gaps;
|
|
|
|
for (i, word) in words.iter().enumerate() {
|
|
justified.push_str(word);
|
|
if i < gaps {
|
|
justified.push_str(&" ".repeat(spaces_per_gap));
|
|
if i < extra_spaces {
|
|
justified.push(' ');
|
|
}
|
|
}
|
|
}
|
|
|
|
return justified;
|
|
}
|
|
|
|
fn read_lines<P>(filename: P) -> io::Result<io::Lines<io::BufReader<File>>>
|
|
where
|
|
P: AsRef<Path>,
|
|
{
|
|
let file = File::open(filename)?;
|
|
Ok(io::BufReader::new(file).lines())
|
|
}
|