| Crates.io | bank-statement-rs |
| lib.rs | bank-statement-rs |
| version | 0.1.0 |
| created_at | 2026-01-13 09:53:17.182057+00 |
| updated_at | 2026-01-13 09:53:17.182057+00 |
| description | Rust library for parsing bank and credit card transaction history from multiple financial export formats |
| homepage | |
| repository | https://github.com/nichmorgan/bank-statement-rs |
| max_upload_size | |
| id | 2039826 |
| size | 85,026 |
bank-statement-rs is a Rust library for parsing bank and credit card transaction history from multiple common financial export formats.
Add this to your Cargo.toml:
[dependencies]
bank-statement-rs = "0.1.0"
The builder pattern provides a fluent and flexible API:
use bank_statement_rs::ParserBuilder;
// Auto-detect format with filename hint
let content = std::fs::read_to_string("statement.qfx")?;
let transactions = ParserBuilder::new()
.content(&content)
.filename("statement.qfx")
.parse()?;
for tx in transactions {
println!("{} | {} | {:?}", tx.date, tx.amount, tx.payee);
}
use bank_statement_rs::ParserBuilder;
let transactions = ParserBuilder::new()
.content(&content)
.parse()?;
use bank_statement_rs::{FileFormat, ParserBuilder};
let transactions = ParserBuilder::new()
.content(&content)
.format(FileFormat::Qfx)
.parse()?;
The ParserBuilder provides the following methods:
.content(&str) - Set the file content to parse.filename(&str) - Set filename for format detection (optional).format(FileFormat) - Explicitly set the format to skip auto-detection (optional).parse() - Parse and return Vec<Transaction> (the default type).parse_into::<T>() - Parse and return Vec<T> where T: TryFrom<ParsedTransaction>Each parser outputs its raw format-specific structures wrapped in a ParsedTransaction enum:
ParsedTransaction::Qfx(QfxTransaction)The library provides a suggested Transaction struct with TryFrom<ParsedTransaction> implemented:
pub struct Transaction {
pub date: NaiveDate,
pub amount: Decimal,
pub payee: Option<String>,
pub transaction_type: String, // e.g., "DEBIT", "CREDIT", "CHECK"
pub fitid: Option<String>, // Financial Institution Transaction ID
pub status: Option<String>,
pub memo: Option<String>,
}
You can create your own transaction structure by implementing TryFrom<ParsedTransaction>:
use bank_statement_rs::{ParsedTransaction, ParserBuilder};
#[derive(Debug)]
struct MyTransaction {
amount: f64,
merchant: String,
date: String,
}
impl TryFrom<ParsedTransaction> for MyTransaction {
type Error = String;
fn try_from(parsed: ParsedTransaction) -> Result<Self, Self::Error> {
match parsed {
ParsedTransaction::Qfx(qfx) => Ok(MyTransaction {
amount: qfx.amount.to_string().parse().unwrap_or(0.0),
merchant: qfx.name.unwrap_or_default(),
date: format!("{:?}", qfx.dt_posted),
}),
// Handle other formats as needed
}
}
}
// Use parse_into to get your custom type
let my_transactions: Vec<MyTransaction> = ParserBuilder::new()
.content(&content)
.parse_into()?;
Implement the Parser trait for your custom format. Each parser should output its own raw format structure:
use bank_statement_rs::Parser;
use serde::{Deserialize, Serialize};
// Define your raw format structure
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CustomTransaction {
pub date: String,
pub amount: String,
pub description: String,
}
pub struct CustomParser;
impl Parser for CustomParser {
type Output = CustomTransaction;
fn is_supported(filename: Option<&str>, content: &str) -> bool {
// Check if this parser can handle the file
filename.map(|f| f.ends_with(".custom")).unwrap_or(false)
}
fn parse(content: &str) -> Result<Vec<CustomTransaction>, String> {
// Parse logic here - return your raw format structures
Ok(vec![])
}
}
// To integrate with the builder, follow these steps:
// 1. Add a variant to ParsedTransaction enum in src/builder.rs:
// ParsedTransaction::Custom(CustomTransaction)
// 2. Add a variant to FileFormat enum in src/builder.rs:
// FileFormat::Custom
// 3. Update FileFormat::parse() to handle the new format
// 4. Update auto-detection logic in ParserBuilder::parse_into()
// 5. Implement TryFrom<CustomTransaction> for Transaction (optional)
See CLAUDE.md for detailed step-by-step instructions on adding new parsers.
See the examples directory for more usage examples:
# Run with example data
cargo run --example parse_qfx
# Parse your own QFX file
cargo run --example parse_qfx path/to/your/statement.qfx
This project is open source.