Skip to content

Repository files navigation

statement-parser

Kotlin Multiplatform library for parsing CSV, OFX/QFX, and PDF bank statements on-device.

Features

  • Multiplatform: Supports Android, iOS, JVM (Desktop/Server).
  • Format Support: Automatic detection and parsing of CSV, OFX/QFX, and PDF.
  • Bank Profiles: Built-in profiles for major UK banks - see Supported Banks.
  • Custom Mapping: Flexibly map any CSV format to a standard transaction model.
  • On-device: All parsing happens locally; no financial data ever leaves the device.

Supported Banks

Bank CSV PDF
Monzo
Starling
NatWest
HSBC ✅ (current account and credit card)
American Express
Barclays
Lloyds
Santander

CSV detection matches on column headers (see CsvBankProfiles); PDF detection matches on first-page text - see Supported PDF Banks below for exactly what each one looks for.

On logos: this table intentionally doesn't embed bank logos. They're trademarked (and usually copyrighted) brand assets, and this project has no affiliation with any bank listed here - hosting their marks alongside "supported" could read as an implied partnership that doesn't exist. If you'd like logos here, the safe route is sourcing them yourself from each bank's own press/media kit under that bank's brand guidelines.

Installation

GitHub Packages

Add the repository to your settings.gradle.kts:

dependencyResolutionManagement {
    repositories {
        maven {
            url = uri("https://maven.pkg.github.com/sporadiclemon/statement-parser")
            credentials {
                username = "your-github-username"
                password = "your-github-token"
            }
        }
    }
}

Then add the dependency:

dependencies {
    implementation("io.github.sporadiclemon:statement-parser:0.1.0")
}

That one coordinate is all you need, on any target (JVM, Android, or iOS) - if you browse the repository directly you'll also see statement-parser-jvm, statement-parser-android, statement-parser-iosarm64, and similar. Those aren't separate releases to choose between; a JVM jar, an Android AAR, and a Kotlin/Native klib are different binary formats with no single file that could be all of them at once, so Gradle Module Metadata publishes each as its own artifact and silently resolves statement-parser to whichever one matches your target. This is how every Kotlin Multiplatform library is published, not something specific to this one.

Optional: persisting a custom ColumnMapping

If you let a user confirm a ColumnMapping for a CSV export from an unrecognised bank and want to remember it, add the separate statement-parser-datastore module:

dependencies {
    implementation("io.github.sporadiclemon:statement-parser:0.1.0")
    implementation("io.github.sporadiclemon:statement-parser-datastore:0.1.0")
}

This is a separate artifact - not a transitive dependency of the core module - so an app that never needs to remember a custom mapping does not pull in AndroidX DataStore, okio, or coroutines just to use StatementParser.

val store = ColumnMappingStore(dataStore) // your app's DataStore<Preferences>
store.save("MyBank", mapping)
val remembered: ColumnMapping? = store.get("MyBank").first()

Usage

val parser = StatementParser()
val content = file.readText()
val format = parser.detectFormat(file.name, content)

val result = parser.parse(content, format).getOrThrow()
result.transactions.forEach { 
    println("${it.date}: ${it.description} (${it.amount})")
}

PDF Parsing

val parser = StatementParser()

// Detect by filename
val format = parser.detectFormat("statement.pdf", "")
// format == StatementFormat.PDF

// Parse a PDF statement
val bytes = file.readBytes()
val result = parser.parsePdf(bytes)                                    // auto-detects bank
val result = parser.parsePdf(bytes, hintProfile = PdfBankProfiles.MONZO) // skip auto-detection

result.getOrThrow().transactions.forEach {
    println("${it.date}: ${it.description} (${it.amount})")
}

Supported PDF Banks

Bank Detected by (first page text)
NatWest "NatWest", "National Westminster"
Monzo "Monzo"
HSBC "HSBC" (current account), "Visa Card statement" (credit card)
Starling "www.starlingbank.com", "Starling Bank Limited"
American Express "American Express"

Starling is matched on its page furniture rather than a bare "Starling", because the word turns up inside payee names on other banks' statements.

Android Setup

PdfBox-Android requires one-time initialisation. In your Application class:

override fun onCreate() {
    super.onCreate()
    PDFBoxResourceLoader.init(applicationContext)
}

Platform Support

Platform PDF Support
Android ✓ (PdfBox-Android)
iOS ✓ (PDFKit, iOS 11+)
JVM ✓ (Apache PDFBox)

License

Apache License 2.0

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages