Skip to content

Add "ngram" search strategy to search_dates - #1351

Merged
serhii73 merged 1 commit into
masterfrom
ngram-search-strategy
Jul 22, 2026
Merged

serhii73 merged 1 commit into
masterfrom
ngram-search-strategy

Conversation

@serhii73

Copy link
Copy Markdown
Collaborator

The new strategy tokenizes the text on characters that never occur inside a date expression and tries to parse token n-grams, longest first, so that the most complete date is found. Compared to the default translation-based "split" strategy it produces more predictable results on noisy real-world text.

The strategy is exposed through the new "strategy" parameter of search_dates and defaults to the existing behavior.

The new strategy tokenizes the text on characters that never occur
inside a date expression and tries to parse token n-grams, longest
first, so that the most complete date is found. Compared to the
default translation-based "split" strategy it produces more
predictable results on noisy real-world text.

The strategy is exposed through the new "strategy" parameter of
search_dates and defaults to the existing behavior.
@codecov

codecov Bot commented Jul 20, 2026 •

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.64286% with 3 lines in your changes missing coverage. Please review.
βœ… Project coverage is 97.07%. Comparing base (762dfff) to head (0470e33).

Files with missing lines Patch % Lines
dateparser/search/ngram_search.py 91.89% 3 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1351      +/-   ##
==========================================
- Coverage   97.12%   97.07%   -0.06%     
==========================================
  Files         235      236       +1     
  Lines        2924     2972      +48     
==========================================
+ Hits         2840     2885      +45     
- Misses         84       87       +3     

β˜” View full report in Codecov by Harness.
πŸ“’ Have feedback on the report? Share it here.

πŸš€ New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@serhii73

Copy link
Copy Markdown
Collaborator Author

Implementation summary

This PR adds an opt-in "ngram" strategy to search_dates, adapting a date-search algorithm from a production date extraction pipeline where it has consistently produced more predictable results than the split-based search on noisy real-world text. The default behavior is unchanged (strategy="split").

How the ngram strategy works

For example, in "Posted on 4 October 1957 by admin":

  1. Tokenize the text on characters that never occur inside a date expression (whitespace and ,|()@), keeping each token's position in the original text.
  2. Drop noise words (on, at, of, a) that may appear between date components.
  3. Scan tokens left to right, trying n-grams of up to 7 tokens, longest first β€” 4 October 1957 by admin βœ— β†’ … β†’ 4 October 1957 βœ“ β€” so the most complete date phrase wins over fragments like October 1957.
  4. Reject blacklisted candidates that parse but are almost always false positives: bare 1–3 digit numbers, #123-style refs, separator runs, single letters.
  5. Parse candidates with DateDataParser(languages=..., use_given_order=True); after a match, scanning resumes past it, so all non-overlapping dates are returned.
  6. Return (substring, datetime) pairs, with substrings taken from the original text (punctuation-stripped), matching the existing search_dates contract.

Changes

  • New module dateparser/search/ngram_search.py with _NgramDateSearch implementing the algorithm above.
  • New strategy parameter on the public search_dates() and DateSearchWithDetection.search_dates(): "split" (default) or "ngram"; invalid values raise ValueError.
  • Language detection and candidate-language resolution are shared between both strategies; the ngram path passes the full candidate-language list to the parser in given order and falls back to settings.DEFAULT_LANGUAGES like the split path.
  • RETURN_TIME_SPAN post-processing extracted into a shared module-level _add_time_span_results() helper, so both strategies have feature parity.
  • 12 new tests in TestNgramSearch: en/fr/ru extraction, noise-word/punctuation handling, blacklist, RELATIVE_BASE, RETURN_TIME_SPAN, module-level passthrough, add_detected_language, None when no dates found, and strategy validation.

Verification

  • tests/test_search.py: 256 passed
  • Full suite (pytest tests): 24072 passed, 20 skipped, 1 xfailed
  • ruff check and ruff format: clean

Usage

from dateparser.search import search_dates

search_dates("Posted on 4 October 1957 by admin", strategy="ngram")
# [('4 October 1957', datetime.datetime(1957, 10, 4, 0, 0))]

@serhii73
serhii73 merged commit cf6d3e5 into master Jul 22, 2026
16 of 18 checks passed
@serhii73
serhii73 deleted the ngram-search-strategy branch July 22, 2026 08:59
@serhii73 serhii73 mentioned this pull request Aug 4, 2026
@AdrianAtZyte AdrianAtZyte mentioned this pull request Sep 27, 2026
5 tasks done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants