From db2bcfe31f8412d9b61e855a4bbcab7cd2a20e81 Mon Sep 17 00:00:00 2001 From: dualfroz Date: Fri, 2 Oct 2026 16:50:12 +0200 Subject: [PATCH] Keep a closing bracket in the word when it closes one inside it --- .../tokenize/methods/03-whitespace/tokenize.js | 18 ++++++++++++++++++ tests/one/tokenize/punctuation.test.js | 16 ++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/src/1-one/tokenize/methods/03-whitespace/tokenize.js b/src/1-one/tokenize/methods/03-whitespace/tokenize.js index 576cf10..d6a541a 100644 --- a/src/1-one/tokenize/methods/03-whitespace/tokenize.js +++ b/src/1-one/tokenize/methods/03-whitespace/tokenize.js @@ -6,6 +6,21 @@ const isNumber = /[\p{Number}\p{Currency_Symbol}]/u const hasAcronym = /^[a-z]\.([a-z]\.)+/i const chillin = /[sn]['’]$/ const isFullNumber = /^[(+\-]?\d+(th|st|nd|rd)?[)+\-]?$/ +const openers = { ')': '(', ']': '[', '}': '{' } + +// does this closing bracket close one inside the word, like 'foo(bar)' +const closesInside = function (chars, start, end) { + const close = chars[end - 1] + let depth = 0 + for (let i = start; i < end - 1; i += 1) { + if (chars[i] === openers[close]) { + depth += 1 + } else if (chars[i] === close) { + depth -= 1 + } + } + return depth > 0 +} const normalizePunctuation = function (str, model) { // quick lookup for allowed pre/post punctuation @@ -68,6 +83,9 @@ const normalizePunctuation = function (str, model) { if ((c === '+' || c === ')') && isFullNumber.test(str.trim())) { break//done } + if (Object.hasOwn(openers, c) && closesInside(chars, start, end)) { + break//keep it + } // punctuation end-- } diff --git a/tests/one/tokenize/punctuation.test.js b/tests/one/tokenize/punctuation.test.js index eaab3e5..ad84528 100644 --- a/tests/one/tokenize/punctuation.test.js +++ b/tests/one/tokenize/punctuation.test.js @@ -29,6 +29,22 @@ test('term punctuation', function (t) { t.end() }) +test('closing bracket inside a word', function (t) { + const arr = [ + ['foo(bar) foo', 'foo(bar)', ' '], + ['foo[bar] foo', 'foo[bar]', ' '], + ['foo{bar} foo', 'foo{bar}', ' '], + ['f(x), y', 'f(x)', ', '], + ['(foo) bar', 'foo', ') '], + ] + arr.forEach(([str, text, post]) => { + const term = nlp(str).docs[0][0] + t.equal(term.text, text, here + `text "${str}"`) + t.equal(term.post, post, here + `post "${str}"`) + }) + t.end() +}) + test('modify existing punctuation', function (t) { const world = nlp.world()