generated from OBJNULL/Dockerized-Rust
Add core modules for statement parsing and CLI args
Includes initial implementations for action, args, parser, and reader modules, supporting PDF reading and argument parsing.
This commit is contained in:
parent
5bddf93ec8
commit
92a666d9bc
4 changed files with 186 additions and 0 deletions
10
project/src/action.rs
Normal file
10
project/src/action.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
// Libraries
|
||||
|
||||
// Structures
|
||||
pub struct Transaction {
|
||||
description: String,
|
||||
date: String,
|
||||
amount: f64,
|
||||
}
|
||||
|
||||
// Implementations
|
50
project/src/args.rs
Normal file
50
project/src/args.rs
Normal file
|
@ -0,0 +1,50 @@
|
|||
// Libraries
|
||||
use clap::{Arg, ArgAction, Command};
|
||||
|
||||
// Structures
|
||||
pub struct Arguments {
|
||||
pub file_input: String,
|
||||
pub file_output: String,
|
||||
}
|
||||
|
||||
// Implementations
|
||||
impl Arguments {
|
||||
// Constructors
|
||||
pub fn new() -> Self {
|
||||
// Creating an Application
|
||||
let matches = Command::new("statement-converter")
|
||||
.about("A service that converts Bank Statement PDF files into CSV files")
|
||||
.version("1.0.0")
|
||||
.arg_required_else_help(true)
|
||||
/*
|
||||
PDF Path
|
||||
*/
|
||||
.arg(
|
||||
Arg::new("file_in")
|
||||
.short('i')
|
||||
.long("file_in")
|
||||
.help("The PDF you want to convert")
|
||||
.action(ArgAction::Set)
|
||||
.required(true),
|
||||
)
|
||||
.arg(
|
||||
Arg::new("file_out")
|
||||
.short('o')
|
||||
.long("file_out")
|
||||
.help("The CSV Path you want to save to")
|
||||
.action(ArgAction::Set)
|
||||
.required(true),
|
||||
)
|
||||
.get_matches();
|
||||
|
||||
// Getting the required arguments
|
||||
let file_input = matches.get_one::<String>("file_in").unwrap().to_string();
|
||||
let file_output = matches.get_one::<String>("file_out").unwrap().to_string();
|
||||
|
||||
// Returning a Result
|
||||
Self {
|
||||
file_input,
|
||||
file_output,
|
||||
}
|
||||
}
|
||||
}
|
95
project/src/parser.rs
Normal file
95
project/src/parser.rs
Normal file
|
@ -0,0 +1,95 @@
|
|||
// Libraries
|
||||
use super::action::Transaction;
|
||||
|
||||
// Enums
|
||||
enum ParserModes {
|
||||
None,
|
||||
Debit,
|
||||
Credit,
|
||||
}
|
||||
|
||||
// Structures
|
||||
pub struct Parser {
|
||||
pub transactions: Vec<Transaction>,
|
||||
mode: ParserModes,
|
||||
paused: bool,
|
||||
|
||||
content: String,
|
||||
}
|
||||
|
||||
// Implementations
|
||||
impl Parser {
|
||||
// Constructors
|
||||
pub fn new(content: String) -> Self {
|
||||
// Return Result
|
||||
Self {
|
||||
transactions: Vec::new(),
|
||||
mode: ParserModes::None,
|
||||
paused: false,
|
||||
|
||||
content,
|
||||
}
|
||||
}
|
||||
|
||||
// Functions
|
||||
fn none(&mut self, line: &str) {
|
||||
// Checking if the line is the beginning of a table
|
||||
if line == "Other withdrawals, debits and service charges" {
|
||||
self.mode = ParserModes::Debit;
|
||||
} else if line == "Deposits, credits and interest" {
|
||||
self.mode = ParserModes::Credit;
|
||||
}
|
||||
}
|
||||
fn debit(&mut self, line: &str) {
|
||||
// Should be pause?
|
||||
if line.contains("continued") {
|
||||
self.paused = true;
|
||||
return;
|
||||
}
|
||||
|
||||
// Checking if it starts with a number
|
||||
if !line.chars().next().map_or(false, |c| c.is_ascii_digit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Print the line
|
||||
println!("Debit: {}", line);
|
||||
}
|
||||
fn credit(&mut self, line: &str) {}
|
||||
|
||||
fn pause_check(&mut self, line: &str) {
|
||||
// Check to see if the line contains "continued"
|
||||
if !line.contains("continued") {
|
||||
return;
|
||||
}
|
||||
|
||||
// We're good to continue now
|
||||
self.paused = false;
|
||||
}
|
||||
|
||||
pub fn start(&mut self) {
|
||||
// Referencing Content
|
||||
let content = self.content.clone();
|
||||
|
||||
// Scanning Line-by-Line through Content
|
||||
for line in content.split('\n') {
|
||||
// Empty line?
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Are we paused?
|
||||
if self.paused {
|
||||
self.pause_check(line);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Switching based on Mode
|
||||
match self.mode {
|
||||
ParserModes::None => self.none(line),
|
||||
ParserModes::Debit => self.debit(line),
|
||||
ParserModes::Credit => self.credit(line),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
31
project/src/reader.rs
Normal file
31
project/src/reader.rs
Normal file
|
@ -0,0 +1,31 @@
|
|||
// Libraries
|
||||
use std::fs::read;
|
||||
use std::io::Result;
|
||||
|
||||
use pdf_extract;
|
||||
|
||||
// Structures
|
||||
pub struct Reader {
|
||||
bytes: Vec<u8>,
|
||||
}
|
||||
|
||||
// Implementations
|
||||
impl Reader {
|
||||
// Constructors
|
||||
pub fn new(path: &String) -> Result<Self> {
|
||||
// Reading the file from the path
|
||||
let bytes = read(path)?;
|
||||
|
||||
// Returning the Result
|
||||
Ok(Self { bytes })
|
||||
}
|
||||
|
||||
// Functions
|
||||
pub fn extract(&self) -> String {
|
||||
// Getting the text from our PDF Bytes
|
||||
let text = pdf_extract::extract_text_from_mem(&self.bytes).unwrap();
|
||||
|
||||
// It's Ok!
|
||||
text
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue