Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions src/gematriya.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,20 @@ for (const [key, val] of Object.entries(heb2num)) {
num2heb[val] = key;
}

/**
* Final (sofit) Hebrew letters mapped to the value of their base form.
* Used only when parsing a gematriya string; `gematriya()` never emits
* these forms, so they are kept out of `heb2num` to avoid clobbering the
* `num2heb` reverse map.
*/
const sofit2num: Record<string, number> = {
ך: 20,
ם: 40,
ן: 50,
ף: 80,
ץ: 90,
} as const;

function num2digits(num: number): number[] {
const digits: number[] = [];
while (num > 0) {
Expand Down Expand Up @@ -93,11 +107,14 @@ export function gematriya(num: number | string): string {
/**
* Converts a string of Hebrew letters to a numerical value.
*
* Only considers the value of Hebrew letters `א` through `ת`.
* Ignores final Hebrew letters such as `ך` (kaf sofit) or `ם` (mem sofit)
* and vowels (nekudot).
* Considers the value of Hebrew letters `א` through `ת`, and the five final
* (sofit) forms `ך`, `ם`, `ן`, `ף`, `ץ`, which count as their base letters
* (20, 40, 50, 80, 90). This matches how Hebrew years are written — e.g.
* `תש״ף` is 780 — since the last letter of a year falls in final form.
* Vowels (nekudot) are ignored.
* @example
* gematriyaStrToNum('תשע״ד'); // 774
* gematriyaStrToNum('תש״ף'); // 780 (final pe)
* gematriyaStrToNum('ט״ו'); // 15
* gematriyaStrToNum('ג׳תשס״א'); // 3761 (thousands prefix)
*/
Expand All @@ -113,7 +130,7 @@ export function gematriyaStrToNum(str: string): number {
str = str.substring(gereshIdx);
}
for (const ch of str) {
const n: number | undefined = heb2num[ch];
const n: number | undefined = heb2num[ch] ?? sofit2num[ch];
if (typeof n === 'number') {
num += n;
}
Expand Down
11 changes: 11 additions & 0 deletions test/gematriya.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,17 @@ test('gematriyaStrToNum', () => {
expect(gematriyaStrToNum('תרי״ג')).toBe(613);
});

test('gematriyaStrToNum-final-letters', () => {
expect(gematriyaStrToNum('תש״ך')).toBe(720);
expect(gematriyaStrToNum('תש״ם')).toBe(740);
expect(gematriyaStrToNum('תש״ן')).toBe(750);
expect(gematriyaStrToNum('תש״ף')).toBe(780);
expect(gematriyaStrToNum('תש״ץ')).toBe(790);
expect(gematriyaStrToNum('תר״ן')).toBe(650);
// final and regular forms of the same letter are equivalent
expect(gematriyaStrToNum('תש״ף')).toBe(gematriyaStrToNum('תש״פ'));
});

test('gematriyaStrToNum-throws', () => {
expect(() => {
gematriyaStrToNum(null as unknown as string);
Expand Down
5 changes: 5 additions & 0 deletions test/hdate.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -608,6 +608,11 @@ test('fromGematriyaString', () => {
expect(HDate.fromGematriyaString('ה׳ אִיָיר ח׳תשס״ה').toString()).toBe('5 Iyyar 8765');
});

test('fromGematriyaString final letters', () => {
expect(HDate.fromGematriyaString('א׳ שבט תש״ף').toString()).toBe("1 Sh'vat 5780");
expect(HDate.fromGematriyaString('א׳ שבט תש״ן').toString()).toBe("1 Sh'vat 5750");
});

test('fromGematriyaString Adar I', () => {
expect(HDate.fromGematriyaString(' ה באדר א תשי"ט ').toString()).toBe('5 Adar I 5719');
});
Expand Down