Skip to content
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- `isValidSwissIbanNumber` string utility function

## [2.0.0] - 2025-07-29

### Added
Expand Down
14 changes: 13 additions & 1 deletion src/lib/string.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { isNullOrEmpty, isNullOrWhitespace, capitalize, uncapitalize, truncate } from "./string";
import { isNullOrEmpty, isNullOrWhitespace, capitalize, uncapitalize, truncate, isValidSwissIbanNumber } from "./string";

describe("string tests", () => {
test.each([
Expand Down Expand Up @@ -120,4 +120,16 @@ describe("string tests", () => {
])("truncate without suffix parameter", (value, maxLength, expected) => {
expect(truncate(value, maxLength)).toBe(expected);
});

test.each([
[null as unknown as string, false],
[undefined as unknown as string, false],
["CH9300762011623852957", true],
["CH93 0000 0000 0000 0000 1", false],
["ch93 0076 2011 6238 5295 7", false],
["DE93 0076 2011 6238 5295 7", false],
["CH93 0076 2011 6238 5295 7", true],
])("Is IBAN valid", (unformattedIbanNumber, expected) => {
Comment thread
neoscie marked this conversation as resolved.
Outdated
expect(isValidSwissIbanNumber(unformattedIbanNumber)).toBe(expected);
});
});
30 changes: 30 additions & 0 deletions src/lib/string.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,33 @@ export function truncate(value: string | undefined, maxLength: number, suffix =

return `${value.slice(0, maxLength)}${suffix}`;
}

/**
* Checks if the provided string is a valid Swiss IBAN number
* @param iBanNumber The provided IBAN number to check
* @returns The result of the IBAN number check
*/
Comment thread
neoscie marked this conversation as resolved.
export function isValidSwissIbanNumber(iBanNumber: string): boolean {
Comment thread
drebrez marked this conversation as resolved.
Outdated
if (!isNullOrEmpty(iBanNumber)) {
const compactIban = iBanNumber.replaceAll(/\s+/g, "");
if (!/^CH\d{19}$/.test(compactIban)) return false;
const rearrangedIban = compactIban.slice(4) + compactIban.slice(0, 4);

const numericStr = Array.from(rearrangedIban, (ch) => {
if (/[A-Z]/.test(ch)) {
const code = ch.codePointAt(0);
// code is never undefined!
return (code! - 55).toString();
}
return ch;
}).join("");

let restOfCalculation = 0;
for (const digit of numericStr) {
restOfCalculation = (restOfCalculation * 10 + Number(digit)) % 97;
}

Comment thread
drebrez marked this conversation as resolved.
return restOfCalculation === 1;
}
return false;
}
Loading