Showing preview only (650K chars total). Download the full file or copy to clipboard to get everything.
Repository: Acreom/quickadd
Branch: master
Commit: 0b3bfc26a734
Files: 69
Total size: 624.0 KB
Directory structure:
gitextract_m6r5n4y6/
├── .codecov.yml
├── .editorconfig
├── .github/
│ └── ISSUE_TEMPLATE.md
├── .gitignore
├── .pyup.yml
├── .travis.yml
├── AUTHORS.rst
├── CONTRIBUTING.rst
├── HISTORY.rst
├── LICENSE
├── MANIFEST.in
├── Makefile
├── README.rst
├── ctparse/
│ ├── __init__.py
│ ├── corpus.py
│ ├── count_vectorizer.py
│ ├── ctparse.py
│ ├── loader.py
│ ├── models/
│ │ ├── __init__.py
│ │ ├── dummy.py
│ │ └── model.pbz
│ ├── nb_estimator.py
│ ├── nb_scorer.py
│ ├── partial_parse.py
│ ├── pipeline.py
│ ├── py.typed
│ ├── rule.py
│ ├── scorer.py
│ ├── time/
│ │ ├── __init__.py
│ │ ├── auto_corpus.py
│ │ ├── corpus.py
│ │ ├── postprocess_latent.py
│ │ └── rules.py
│ ├── timers.py
│ └── types.py
├── datasets/
│ ├── README.rst
│ └── timeparse_corpus.json
├── docs/
│ ├── Makefile
│ ├── authors.rst
│ ├── conf.py
│ ├── contributing.rst
│ ├── ctparse.rst
│ ├── ctparse.time.rst
│ ├── dataset.rst
│ ├── history.rst
│ ├── index.rst
│ ├── installation.rst
│ ├── make.bat
│ ├── modules.rst
│ ├── readme.rst
│ └── usage.rst
├── mypy.ini
├── requirements.txt
├── requirements_dev.txt
├── scripts/
│ └── train_default_model.py
├── setup.cfg
├── setup.py
├── tests/
│ ├── __init__.py
│ ├── test_corpus.py
│ ├── test_count_vectorizer.py
│ ├── test_ctparse.py
│ ├── test_partialparse.py
│ ├── test_regressions.py
│ ├── test_rule.py
│ ├── test_scorer.py
│ ├── test_time_rules.py
│ ├── test_timers.py
│ └── test_types.py
└── tox.ini
================================================
FILE CONTENTS
================================================
================================================
FILE: .codecov.yml
================================================
comment: off
================================================
FILE: .editorconfig
================================================
# http://editorconfig.org
root = true
[*]
indent_style = space
indent_size = 4
trim_trailing_whitespace = true
insert_final_newline = true
charset = utf-8
end_of_line = lf
[*.bat]
indent_style = tab
end_of_line = crlf
[LICENSE]
insert_final_newline = false
[Makefile]
indent_style = tab
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
* ctparse - Parse natural language time expressions in pytho version:
* Python version:
* Operating System:
### Description
Describe what you were trying to get done.
Tell us what happened, what went wrong, and what you expected to happen.
### What I Did
```
Paste the command(s) you ran and the output.
If there was a crash, please include the traceback here.
```
================================================
FILE: .gitignore
================================================
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
*.egg-info/
.installed.cfg
*.egg
.idea/
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# Jupyter Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# SageMath parsed files
*.sage.py
# dotenv
.env
# virtualenv
.venv
venv/
ENV/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
# pytest
.pytest_cache/
# system
.DS_Store
# vscode
.vscode
================================================
FILE: .pyup.yml
================================================
# autogenerated pyup.io config file
# see https://pyup.io/docs/configuration/ for all available options
update: insecure
================================================
FILE: .travis.yml
================================================
language: python
sudo: required
dist: xenial
python:
- 3.8
- 3.7
- 3.6
install: pip install -U tox-travis codecov
script: tox
after_success:
codecov
================================================
FILE: AUTHORS.rst
================================================
=======
Credits
=======
Development Lead
----------------
* Sebastian Mika <sebastian.mika@comtravo.com>
Contributors
------------
* Gabriele Lanaro <gabriele.lanaro@comtravo.com>
================================================
FILE: CONTRIBUTING.rst
================================================
============
Contributing
============
Contributions are welcome, and they are greatly appreciated! Every little bit
helps, and credit will always be given.
You can contribute in many ways:
Add Rules & Increase Coverage
-----------------------------
If you find an expressions that ``ctparse`` can not resolve correctly
but you feel it should do, you can adjust the existing rules or add a
new one.
The following steps are probably a helpful guideline.
* Add your case to the ``corpus.py`` file and run the corpus tests
using ``py.test tests/test_run_corpus.py``. Now basically two things can happen:
#. **The tests pass**, which means ``ctparse`` can correctly resolve
the expression. It might not score it highest. To check this,
rebuild the model and try parsing the expression again:
.. code:: bash
make train
To avoid issues with reloading, please restart the python
interpreter after regenerating the model.
If this fixes the issue please commit the updated ``corpus.py``
and the updated model as a pull request (PR) on GitHub, see this guide for
more information on what pull requests are and how to create them
https://help.github.com/articles/creating-a-pull-request/.
The scoring can be influenced by
adding more structurally identical examples to the corpus. Seeing
more samples where a specific sequence of rule applications leads
to the correct ranking will drive the model to favor these. This
comes, however, at the potential price of downranking certain
other production sequences. Although it would generally be
considered more favorable to add varying test cases (e.g. in
different languages, slight variation) to the corpus, the same
string can also just be duplicated to achive this *implict
up-weightning* effect. The examples that are intended to influence the scoring,
as opposed to the ones used to develop new rules, are usually appended
to the file ``auto_corpus.py```.
#. **The tests fail**: if this is because not all tests in the
corpus pass, i.e. you get an error message like the following::
ctparse.py 527 WARNING failure: target "Time[]{2019-X-X X:X (X/X)}" never produced in "2019"
ctparse.py 532 WARNING failure: "Time[]{2019-X-X X:X (X/X)}" not always produced
* If the tests fail, run ``ctparse`` in debug mode to see what goes wrong:
.. code:: python
import logging
from ctparse import ctparse
from ctparse.ctparse import logger
from datetime import datetime
logger.addHandler(logging.StreamHandler())
logger.setLevel(logging.DEBUG)
# Set reference time
ts = datetime(2018, 3, 12, 14, 30)
r = list(ctparse('May 5th', ts=ts, debug=True))
This gives you plenty of debugging output. First you will see
the individual regular expressions that were matched (and the time
this took)::
================================================================================
-> matching regular expressions
regex: RegexMatch[0-3]{114:May}
regex: RegexMatch[4-5]{133:5}
regex: RegexMatch[4-7]{135:5th}
regex: RegexMatch[4-5]{134:5}
regex: RegexMatch[4-5]{148:5}
time in _match_regex: 1ms
================================================================================
Each line has the form ``regex: RegexMatch[0-3]{114:May}`` and describes
the matched span in the text ``[0-3]``, the ID of the matching expression
``114`` and the surface string that the expression matched ``May``.
If relevant parts of your expression were not picked up, this is an
indicator that you should either modify an existing regular
expression or need to add a new rule (see below).
Next you see the unique sub-sequences constructed based on these
regular expressions (plus again the time used to build them)::
================================================================================
-> building initial stack
regex stack (RegexMatch[0-3]{114:May}, RegexMatch[4-7]{135:5th})
regex stack (RegexMatch[0-3]{114:May}, RegexMatch[4-5]{148:5})
regex stack (RegexMatch[0-3]{114:May}, RegexMatch[4-5]{134:5})
regex stack (RegexMatch[0-3]{114:May}, RegexMatch[4-5]{133:5})
time in _regex_stack: 0ms
initial stack length: 4
stack length after relative match length: 1
stack length after max stack depth limit: 1
================================================================================
This is followed by a summary of how many applicable rules there are
per initial stack element::
================================================================================
-> checking rule applicability
of 75 total rules 20 are applicable in (RegexMatch[0-3]{114:May}, RegexMatch[4-7]{135:5th})
time in _filter_rules: 0ms
================================================================================
================================================================================
-> checking rule applicability
of 75 total rules 20 are applicable in (RegexMatch[0-3]{114:May}, RegexMatch[4-5]{148:5})
time in _filter_rules: 0ms
================================================================================
...
Again, if you do not see any sequence that captures all relevant
parts of your input, you may need to modify the regular expressions
or add new ones via rules.
Finally you see a list of productions that are applied to stack
elements, where for each applicable rule the rule name and the new
stack sequence are printed, e.g.::
--------------------------------------------------------------------------------
producing on (RegexMatch[0-3]{114:May}, RegexMatch[4-7]{135:5th}), score=-0.13
ruleMonthMay -> (Time[0-3]{X-05-X X:X (X/X)}, RegexMatch[4-7]{135:5th}), score=1.41
ruleDOM2 -> (RegexMatch[0-3]{114:May}, Time[4-7]{X-X-05 X:X (X/X)}), score=1.38
added 2 new stack elements, depth after trunc: 2
--------------------------------------------------------------------------------
If no productions could be applied to a stack element the emitted
results are printed::
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
no rules applicable: emitting
=> Time[0-7]{2018-05-05 X:X (X/X)}, score=15.91,
--------------------------------------------------------------------------------
If the desired production does not show up, but the regular
expressions look fine and the initial stack elements as well, try
increasing the ``max_stack_depth`` parameter, i.e. run
``ctparse(..., max_stack_depth=0)``. Also make sure that the
``timeout`` parameter is not set. Maybe ``ctparse`` is able to
generate the resolution but it is too deep in the stack.
Adding a rule
~~~~~~~~~~~~~
When adding rules try to follow these guidelines:
1. Be as general as possible: instead of writing one long regular
expression that matches only a specific case, check whether you can
rather divide your pattern in production parts + some regular
expressions. For example, if you have a very specific way to
speficy the year of a date in mind, it might do no harm to just
allow anything that with ``predicate('hasDate')`` plus your
specific year expression, i.e.
.. code:: python
@rule(predicate('hasDate'), r'your funky year')
2. Keep your regex as general as possible, but avoid regular
expressions that are likely to generate many "false positives". Often
that can be prevented by using positive or negative lookaheads and
lookbehinds to keep the context sane (see `Lookaround
<https://www.regular-expressions.info/lookaround.html>`_ on the
excellent regular-expression.info site).
3. Make sure your production covers corner cases and matches the
``ctparse`` opinion to resolve to times in the near future but -
unless explicit -- never in the past (relative to the reference
time). Also make sure it favors the close future over the further
future.
Other Types of Contributions
----------------------------
Report Bugs
~~~~~~~~~~~
Report bugs at https://github.com/comtravo/ctparse/issues.
If you are reporting a bug, please include:
* Your operating system name and version.
* Any details about your local setup that might be helpful in troubleshooting.
* Detailed steps to reproduce the bug.
Fix Bugs
~~~~~~~~
Look through the GitHub issues for bugs. Anything tagged with "bug" and "help
wanted" is open to whoever wants to implement it.
Implement Features
~~~~~~~~~~~~~~~~~~
Look through the GitHub issues for features. Anything tagged with "enhancement"
and "help wanted" is open to whoever wants to implement it.
Write Documentation
~~~~~~~~~~~~~~~~~~~
ctparse - Parse natural language time expressions in pytho could always use more documentation, whether as part of the
official ctparse - Parse natural language time expressions in pytho docs, in docstrings, or even on the web in blog posts,
articles, and such.
Submit Feedback
~~~~~~~~~~~~~~~
The best way to send feedback is to file an issue at https://github.com/comtravo/ctparse/issues.
If you are proposing a feature:
* Explain in detail how it would work.
* Keep the scope as narrow as possible, to make it easier to implement.
* Remember that this is a volunteer-driven project, and that contributions
are welcome :)
Get Started!
------------
Ready to contribute? Here's how to set up `ctparse` for local development.
1. Fork the `ctparse` repo on GitHub.
2. Clone your fork locally::
$ git clone git@github.com:your_name_here/ctparse.git
3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development::
$ mkvirtualenv ctparse
$ cd ctparse/
$ python setup.py develop
4. Create a branch for local development::
$ git checkout -b name-of-your-bugfix-or-feature
Now you can make your changes locally.
5. When you're done making changes, check that your changes pass flake8 and the
tests, including testing other Python versions with tox::
$ flake8 ctparse tests
$ python setup.py test or py.test
$ tox
To get flake8 and tox, just pip install them into your virtualenv.
6. Commit your changes and push your branch to GitHub::
$ git add .
$ git commit -m "Your detailed description of your changes."
$ git push origin name-of-your-bugfix-or-feature
7. Submit a pull request through the GitHub website.
Pull Request Guidelines
-----------------------
Before you submit a pull request, check that it meets these guidelines:
1. The pull request should include tests.
2. If the pull request adds functionality, the docs should be updated. Put
your new functionality into a function with a docstring, and add the
feature to the list in README.rst.
3. The pull request should work for Python 3.6., 3.7. and 3.8. Check
https://travis-ci.org/comtravo/ctparse/pull_requests
and make sure that the tests pass for all supported Python versions.
Tips
----
To run a subset of tests::
$ py.test tests.test_ctparse
Deploying
---------
A reminder for the maintainers on how to deploy.
Make sure all your changes are committed (including an entry in HISTORY.rst).
Then run on the ``master`` branch::
$ bumpversion patch # possible: major / minor / patch
$ git push
$ git push --tags
$ make release
You will need a username and password to upload to pypi (might be
automated on Travis).
================================================
FILE: HISTORY.rst
================================================
=======
History
=======
0.3.0 (2021-02-01)
------------------
* Removed latent rules regarding times (latent rules regarding dates are still present)
* Added latent_time option to customize the new behavior, defauld behavior is backwards-compatible
0.2.1 (2020-05-27)
------------------
* Update development dependencies
* Add flake8-bugbear and fixed issues
0.2.0 (2020-04-23)
------------------
* Implemented new type `Duration`, to handle lengths of time
* Adapted the dataset to include `Duration`
* Implemented basic rule to merge `Duration`, `Time` and `Interval` in simple cases.
* Created a make target to train the model `make train`
0.1.0 (2020-03-20)
------------------
* Major refactor of code underlying predictive model
* Based on a contribution from @bharathi-srini: replace naive bayes from sklearn by own implementation
* Thus remove dependencies on numpy, scipy, scikit-learn
* Predictions are much faster: 97/s in the old vs. 239/s in the new code base
* Performance identical
* Deprecate support for python 3.5, add 3.8
* Add more strict type checking rules (mypy.ini)
* Force black code formatting, make this a linter step, "black" all code
0.0.47 (2020-02-28)
-------------------
* Allow overlapping matches of regular expression when generating inital stack of "tokens"
0.0.46 (2020-02-26)
-------------------
* Implemented heuristics to detect (albeit imperfectly) military times
0.0.44 (2019-11-05)
-------------------
* Released time corpus
* Implemented training model using ctparse corpus
0.0.43 (2019-11-01)
-------------------
* Added slash as a general separator
* Added ruleTODTOD (to support expression like afternoon/evening)
0.0.42 (2019-10-30)
-------------------
* Removed nb module
* Fix for two digit years
* Freshly retrained model binary file
0.0.41 (2019-10-29)
-------------------
* Fix run_corpus refactoring bug
* Implemented retraining utilities
0.0.40 (2019-10-25)
-------------------
* update develop dependencies
* remove unused Protocol import from typing_extensions
0.0.39 (2019-10-24)
-------------------
* split ctparse file into several different modules
* added types to public interface
* introduced the Scorer abstraction to implement richer scoring strategies
0.0.38 (2018-11-05)
-------------------
* Added python 3.7 to supported versions (fix on travis available)
0.0.8 (2018-06-07)
------------------
* First release on PyPI.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2018, Sebastian Mika, Comtravo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MANIFEST.in
================================================
include AUTHORS.rst
include CONTRIBUTING.rst
include HISTORY.rst
include LICENSE
include README.rst
include requirements.txt
recursive-include tests *
recursive-exclude * __pycache__
recursive-exclude * *.py[co]
recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif
================================================
FILE: Makefile
================================================
.PHONY: clean clean-test clean-pyc clean-build docs help
.DEFAULT_GOAL := help
define BROWSER_PYSCRIPT
import os, webbrowser, sys
try:
from urllib import pathname2url
except:
from urllib.request import pathname2url
webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1])))
endef
export BROWSER_PYSCRIPT
define PRINT_HELP_PYSCRIPT
import re, sys
for line in sys.stdin:
match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line)
if match:
target, help = match.groups()
print("%-20s %s" % (target, help))
endef
export PRINT_HELP_PYSCRIPT
BROWSER := python -c "$$BROWSER_PYSCRIPT"
help:
@python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST)
clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts
clean-build: ## remove build artifacts
rm -fr build/
rm -fr dist/
rm -fr .eggs/
find . -name '*.egg-info' -exec rm -fr {} +
find . -name '*.egg' -exec rm -f {} +
clean-pyc: ## remove Python file artifacts
find . -name '*.pyc' -exec rm -f {} +
find . -name '*.pyo' -exec rm -f {} +
find . -name '*~' -exec rm -f {} +
find . -name '__pycache__' -exec rm -fr {} +
clean-test: ## remove test and coverage artifacts
rm -fr .tox/
rm -f .coverage
rm -fr htmlcov/
rm -fr .pytest_cache
lint: ## check style with flake8
black --check ctparse tests
flake8 ctparse tests
mypy -p ctparse -p tests
test: ## run tests quickly with the default Python
py.test
test-all: ## run tests on every Python version with tox
tox
train:
python scripts/train_default_model.py --legacy --dataset datasets/timeparse_corpus.json
coverage: ## check code coverage quickly with the default Python
coverage run --source ctparse -m pytest
coverage report -m
coverage html
$(BROWSER) htmlcov/index.html
docs: ## generate Sphinx HTML documentation, including API docs
rm -f docs/ctparse.rst
rm -f docs/modules.rst
sphinx-apidoc -o docs/ ctparse
$(MAKE) -C docs clean
$(MAKE) -C docs html
$(BROWSER) docs/_build/html/index.html
servedocs: docs ## compile the docs watching for changes
watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D .
release: dist ## package and upload a release
twine upload dist/*
dist: clean ## builds source and wheel package
python setup.py sdist
python setup.py bdist_wheel
ls -l dist
install: clean ## install the package to the active Python's site-packages
python setup.py install
================================================
FILE: README.rst
================================================
===========================================================
quickadd
===========================================================
quickadd is a natural language date & time parser written in python. It builds on top of ctparse_ and is an actively maintained fork by Martin Antos.
Installation
----------
With ``pip install -e git+https://github.com/Acreom/quickadd.git#egg=quickadd``
or run ``python setup.py install`` in the root directory after forking.
Main upgrades include:
----------
**Recurring events**
.. code:: python
r = ctparse("beer daily 4pm")
r.resolution
Recurring[5-14]{daily 1 2021-05-09 16:00 (X/X) 2021-05-09 16:00 (X/X)}
r = ctparse("beer every thursday 4")
r.resolution
Recurring[5-21]{weekly 1 2021-04-15 16:00 (X/X) 2021-04-15 16:00 (X/X)}
r = ctparse("beer every friday 9-5")
r.resolution
Recurring[5-21]{weekly 1 2021-05-14 09:00 (X/X) 2021-05-14 17:00 (X/X)}
r = ctparse("beer september 24 / beer every 24.9")
r.resolution
Recurring[5-21]{YEARLY 1 2021-09-24 (X/X) 2021-09-24 (X/X)}
r = ctparse("beer thursdays 3pm and wednesdays 4pm")
r.resolution
RecurringArray[5-37]{
Recurring instance: weekly 1 2021-05-13 15:00 (X/X) 2021-05-13 15:00 (X/X)
Recurring instance: weekly 1 2021-05-12 16:00 (X/X) 2021-05-12 16:00 (X/X)
}
r = ctparse("beer 9pm weekdays")
r.resolution
RecurringArray[5-17]{
Recurring instance: weekly 1 2021-05-10 21:00 (X/X) 2021-05-10 21:00 (X/X)
Recurring instance: weekly 1 2021-05-11 21:00 (X/X) 2021-05-11 21:00 (X/X)
Recurring instance: weekly 1 2021-05-12 21:00 (X/X) 2021-05-12 21:00 (X/X)
Recurring instance: weekly 1 2021-05-13 21:00 (X/X) 2021-05-13 21:00 (X/X)
Recurring instance: weekly 1 2021-05-14 21:00 (X/X) 2021-05-14 21:00 (X/X)}
**More rules**
ruleNextFrequency
.. code:: python
#reference date = Dec 13th 2022
r = ctparse("code next week 4pm")
r.resolution
Time[5-18]{2022-12-20 16:00
r = ctparse("code next month")
r.resolution
Time[5-15]{2023-01-13 X:X (X/X)}
ruleLastDOM
.. code:: python
#reference date = Dec 13th 2022
r = ctparse("code last monday of the month")
r.resolution
Time[5-17]{2022-12-26 X:X (X/X)}
rrule_ **support**
.. code:: python
r.resolution.to_rrule()
Out[4]: 'RRULE:FREQ=DAILY;COUNT=1'
**Subject extraction**
.. code:: python
r = ctparse("beers and burgers friday 8pm-9pm")
r.subject
Out[2]: 'beers and burgers'
**PM bias**
.. code:: python
r = ctparse("fix the issue tmrw 2")
r.resolution
Time[14-20]{2022-11-23 14:00 (X/X)}
r = ctparse("fix the issue tmrw 2", pm_bias=False)
r.resolution
Time[14-20]{2022-11-23 02:00 (X/X)}
**Rules for ambigious natural language expressions**
.. code:: python
r = ctparse("code 9-5")
r.resolution
Interval[0-0]{2022-11-23 09:00 (X/X) - 2022-11-23 17:00 (X/X)}
**US/EU date format**
.. code:: python
r = ctparse("fix the issue 5.3")
r.resolution
Time[14-17]{2023-03-05 X:X (X/X)}
r = ctparse("fix the issue 5.3", date_format="US")
r.resolution
Time[14-17]{2023-05-03 X:X (X/X)}
**Rule combinations**
.. code:: python
r = ctparse("beer in 3 days 4pm")
r.resolution
Time[5-18]{2021-05-12 16:00 (X/X)}
r = ctparse("beer in 3 days 4pm every week")
r.resolution
Recurring[5-29]{weekly 1 2021-05-12 16:00 (X/X) 2021-05-12 16:00 (X/X)}
r = ctparse("beer every friday 4-6:30pm")
r.resolution
Recurring[5-26]{WEEKLY 1 2022-11-25 16:00 (X/X) 2022-11-25 18:30 (X/X)}
``+`` **performance improvements**
Base Capabilities
----------
| **Time**
.. code:: python
"beer thursday 4"
Time[5-15]{2021-05-13 16:00 (X/X)}
| **Interval**
.. code:: python
"beer 4-6"
Interval[0-0]{2021-05-09 16:00 (X/X) - 2021-05-09 18:00 (X/X)}
| **Duration**
.. code:: python
"beer in 4 hours"
Duration[5-15]{4 hours}
Ctparse
----------
The package ``ctparse`` is a pure python package to parse time
expressions from natural language (i.e. strings). In many ways it builds
on similar concepts as Facebook’s ``duckling`` package
(https://github.com/facebook/duckling). However, for the time being it
only targets times and only German and English text.
In principle ``ctparse`` can be used to **detect** time expressions in a
text, however its main use case is the semantic interpretation of such
expressions. Detecting time expressions in the first place can - to our
experience - be done more efficiently (and precisely) using e.g. CRFs or
other models targeted at this specific task.
``ctparse`` is designed with the use case in mind where interpretation
of time expressions is done under the following assumptions:
- All expressions are relative to some pre-defined reference times
- Unless explicitly specified in the time expression, valid resolutions
are in the future relative to the reference time (i.e. ``12.5.`` will
be the next 12th of May, but ``12.5.2012`` should correctly resolve
to the 12th of May 2012).
- If in doubt, resolutions in the near future are more likely than
resolutions in the far future (not implemented yet, but any
resolution more than i.e. 3 month in the future is extremely
unlikely).
The specific comtravo use-case is resolving time expressions in booking
requests which almost always refer to some point in time within the next
4-8 weeks.
``ctparse`` currently is language agnostic and supports German and
English expressions. This might get an extension in the future. The main
reason is that in real world communication more often than not people
write in one language (their business language) but use constructs to
express times that are based on their mother tongue and/or what they
believe to be the way to express dates in the target language. This
leads to text in German with English time expressions and vice-versa.
Using a language detection upfront on the complete original text is for
obvious no solution - rather it would make the problem worse.
Example
-------
.. code:: python
from ctparse import ctparse
from datetime import datetime
# Set reference time
ts = datetime(2018, 3, 12, 14, 30)
ctparse('May 5th 2:30 in the afternoon', ts=ts)
This should return a ``Time`` object represented as
``Time[0-29]{2018-05-05 14:30 (X/X)}``, indicating that characters
``0-29`` were used in the resolution, that the resolved date time is the
5th of May 2018 at 14:30 and that this resolution is neither based on a
day of week (first ``X``) nor a part of day (second ``X``).
Latent time
~~~~~~~~~~~
Normally, ``ctparse`` will anchor time expressions to the reference time.
For example, when parsing the time expression ``8:00 pm``, ctparse will
resolve the expression to 8 pm after the reference time as follows
.. code:: python
parse = ctparse("8:00 pm", ts=datetime(2020, 1, 1, 7, 0), latent_time=True) # default
# parse.resolution -> Time(2020, 1, 1, 20, 00)
This behavior can be customized using the option ``latent_time=False``, which will
return a time resolution not anchored to a particular date
.. code:: python
parse = ctparse("8:00 pm", ts=datetime(2020, 1, 1, 7, 0), latent_time=False)
# parse.resolution -> Time(None, None, None, 20, 00)
Implementation
--------------
``ctparse`` - as ``duckling`` - is a mixture of a rule and regular
expression based system + some probabilistic modeling. In this sense it
resembles a PCFG.
Rules
~~~~~
At the core ``ctparse`` is a collection of production rules over
sequences of regular expressions and (intermediate) productions.
Productions are either of type ``Time``, ``Interval``, ``Duration`` or ``Recurring`` and can
have certain predicates (e.g. whether a ``Time`` is a part of day like
``'afternoon'``).
A typical rule than looks like this:
.. code:: python
@rule(predicate('isDate'), dimension(Interval))
I.e. this rule is applicable when the intermediate production resulted
in something that has a date, followed by something that is in interval
(like e.g. in ``'May 5th 9-10'``).
The actual production is a python function with the following signature:
.. code:: python
@rule(predicate('isDate'), dimension(Interval))
def ruleDateInterval(ts, d, i):
"""
param ts: datetime - the current refenrence time
d: Time - a time that contains at least a full date
i: Interval - some Interval
"""
if not (i.t_from.isTOD and i.t_to.isTOD):
return None
return Interval(
t_from=Time(year=d.year, month=d.month, day=d.day,
hour=i.t_from.hour, minute=i.t_from.minute),
t_to=Time(year=d.year, month=d.month, day=d.day,
hour=i.t_to.hour, minute=i.t_to.minute))
This production will return a new interval at the date of
``predicate('isDate')`` spanning the time coded in
``dimension(Interval)``. If the latter does code for something else than
a time of day (TOD), no production is returned, e.g. the rule matched
but failed.
Technical Background
~~~~~~~~~~~~~~~~~~~~
Some observations on the problem:
- Each rule is a combination of regular expressions and productions.
- Consequently, each production must originate in a sequence of regular
expressions that must have matched (parts of) the text.
- Hence, only subsequence of **all** regular expressions in **all**
rules can lead to a successful production.
To this end the algorithm proceeds as follows:
1. Input a string and a reference time
2. Find all matches of all regular expressions from all rules in the
input strings. Each regular expression is assigned an identifier.
3. Find all distinct sequences of these matches where two matches do not
overlap nor have a gap inbetween
4. To each such subsequence apply all rules at all possible positions
until no further rules can be applied - in which case one solution is
produced
Obviously, not all sequences of matching expressions and not all
sequences of rules applied on top lead to meaningful results. Here the
**P**\ CFG kicks in:
- Based on example data (``corpus.py``) a model is calibrated to
predict how likely a production is to lead to a/the correct result.
Instead of doing a breadth first search, the most promising
productions are applied first.
- Resolutions are produced until there are no more resolutions or a
timeout is hit.
- Based on the same model from all resolutions the highest scoring is
returned.
.. _ctparse: https://github.com/comtravo/ctparse
.. _rrule: https://dateutil.readthedocs.io/en/stable/rrule.html
Credits
-------
This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template.
.. _Cookiecutter: https://github.com/audreyr/cookiecutter
.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage
================================================
FILE: ctparse/__init__.py
================================================
"""ctparse - parse time expressions in strings
.. moduleauthor:: Comtravo
"""
__author__ = """Sebastian Mika"""
__email__ = "sebastian.mika@comtravo.com"
__version__ = "__version__ = '0.3.0'"
from .ctparse import ctparse, ctparse_gen # noqa
================================================
FILE: ctparse/corpus.py
================================================
import json
import logging
from datetime import datetime
from typing import Callable, Iterable, List, NamedTuple, Sequence, Tuple, TypeVar, Union
from tqdm import tqdm
from .ctparse import ctparse_gen
from .scorer import DummyScorer, Scorer
from .types import Artifact, Duration, Interval, Time
logger = logging.getLogger(__name__)
# A triplet of text, reference timestamp and correct parse.
# It can be used as raw data to build datasets for ctparse.
TimeParseEntry = NamedTuple(
"TimeParseEntry", [("text", str), ("ts", datetime), ("gold", Artifact)],
)
T = TypeVar("T")
def make_partial_rule_dataset(
entries: Sequence[TimeParseEntry],
scorer: Scorer,
timeout: Union[float, int],
max_stack_depth: int,
relative_match_len: float = 1.0,
progress: bool = False,
) -> Iterable[Tuple[List[str], bool]]:
"""Build a data set from an iterable of TimeParseEntry.
The text is run through ctparse and all parses (within the specified timeout,
max_stack_depth and scorer) are obtained. Each parse contains a sequence
of rules (see ``CTParse.rules``) used to produce that parse.
A dataset is generated by taking every possible partial rule and assigning to it
a boolean indicating if that partial sequence did lead to a successful parse.
If `progress` is ``True``, display a progress bar.
Example:
rule sequence: [r1, r2, r3]
parse_is_correct: True
[r1] -> True
[r1, r2] -> True
[r1, r2, r3] -> True
"""
# If we look at the signature for a scorer, the score is obtained from:
# (text, reference_time, partial_parse) and optionally a production for a
# partial parse.
# Clearly, if we were to make a general scorer for the dataset, we would need
# all of these features. It is possible to achieve that by tracking the list of
# partial parses that led to a correct parse. Unfortunately we don't have the
# full history with the current implementation, however we can obtain a dataset
# of (text, reference_time, rule_ids) quite easily, because the rule is a linear
# list.
if progress:
entries_it = _progress_bar(
entries,
total=len(entries),
status_text=lambda entry: " {: <70}".format(entry.text),
)
else:
entries_it = entries
for entry in entries_it:
for parse in ctparse_gen(
entry.text,
entry.ts,
relative_match_len=relative_match_len,
timeout=timeout,
max_stack_depth=max_stack_depth,
scorer=scorer,
latent_time=False,
):
# TODO: we should make sure ctparse_gen never returns None. If there is no
# result it should return an empty list
if parse is None:
continue
y = parse.resolution == entry.gold
# Build data set, one sample for each applied rule in
# the sequence of rules applied in this production
# *after* the matched regular expressions
for i in range(1, len(parse.production) + 1):
X = [str(p) for p in parse.production[:i]]
yield X, y
def _progress_bar(
it: Iterable[T], total: int, status_text: Callable[[T], str]
) -> Iterable[T]:
# Progress bar that can update text
pbar = tqdm(it, total=total)
for val in pbar:
pbar.set_description(status_text(val))
yield val
def load_timeparse_corpus(fname: str) -> Sequence[TimeParseEntry]:
"""Load a corpus from disk.
For more information about the format of the time parse corpus,
refer to the documentation.
"""
with open(fname, "r", encoding="utf-8") as fd:
entries = json.load(fd)
return [
TimeParseEntry(
text=e["text"],
ts=datetime.strptime(e["ref_time"], "%Y-%m-%dT%H:%M:%S"),
gold=parse_nb_string(e["gold_parse"]),
)
for e in entries
]
def parse_nb_string(gold_parse: str) -> Union[Time, Interval, Duration]:
"""Parse a Time, Interval or Duration from their no-bound string representation.
The no-bound string representations are generated from ``Artifact.nb_str``.
"""
if gold_parse.startswith("Time"):
return Time.from_str(gold_parse[7:-1])
if gold_parse.startswith("Interval"):
return Interval.from_str(gold_parse[11:-1])
if gold_parse.startswith("Duration"):
return Duration.from_str(gold_parse[11:-1])
else:
raise ValueError("'{}' has an invalid format".format(gold_parse))
def run_corpus(
corpus: Sequence[Tuple[str, str, Sequence[str]]]
) -> Tuple[List[List[str]], List[bool]]:
"""Load the corpus (currently hard coded), run it through ctparse with
no timeout and no limit on the stack depth.
The corpus passes if ctparse generates the desired solution for
each test at least once. Otherwise it fails.
While testing this, a labeled data set (X, y) is generated based
on *all* productions. Given a final production p, based on initial
regular expression matches r_0, ..., r_n, which are then
subsequently transformed using production rules p_0, ..., p_m,
will result in the samples
[r_0, ..., r_n, p_0, 'step_0']
[r_0, ..., r_n, p_0, p_1, 'step_1']
...
[r_0, ..., r_n, p_0, ..., p_m, 'step_m']
All samples from one production are given the same label which indicates if
the production was correct.
To build a similar datasets without the strict checking, use
`make_partial_rule_dataset`
"""
at_least_one_failed = False
# pos_parses: number of parses that are correct
# neg_parses: number of parses that are wrong
# pos_first_parses: number of first parses generated that are correct
# pos_best_scored: number of correct parses that have the best score
pos_parses = neg_parses = pos_first_parses = pos_best_scored = 0
total_tests = 0
Xs = []
ys = []
for target, ts, tests in tqdm(corpus):
ts = datetime.strptime(ts, "%Y-%m-%dT%H:%M")
all_tests_pass = True
for test in tests:
one_prod_passes = False
first_prod = True
y_score = []
for parse in ctparse_gen(
test,
ts,
relative_match_len=1.0,
timeout=0,
max_stack_depth=0,
scorer=DummyScorer(),
latent_time=False,
):
assert parse is not None
y = parse.resolution.nb_str() == target
# Build data set, one sample for each applied rule in
# the sequence of rules applied in this production
# *after* the matched regular expressions
for i in range(1, len(parse.production) + 1):
Xs.append([str(p) for p in parse.production[:i]])
ys.append(y)
one_prod_passes |= y
pos_parses += int(y)
neg_parses += int(not y)
pos_first_parses += int(y and first_prod)
first_prod = False
y_score.append((parse.score, y))
if not one_prod_passes:
logger.warning(
'failure: target "{}" never produced in "{}"'.format(target, test)
)
pos_best_scored += int(max(y_score, key=lambda x: x[0])[1])
total_tests += len(tests)
all_tests_pass &= one_prod_passes
if not all_tests_pass:
logger.warning('failure: "{}" not always produced'.format(target))
at_least_one_failed = True
logger.info(
"run {} tests on {} targets with a total of "
"{} positive and {} negative parses (={})".format(
total_tests, len(corpus), pos_parses, neg_parses, pos_parses + neg_parses
)
)
logger.info(
"share of correct parses in all parses: {:.2%}".format(
pos_parses / (pos_parses + neg_parses)
)
)
logger.info(
"share of correct parses being produced first: {:.2%}".format(
pos_first_parses / (pos_parses + neg_parses)
)
)
logger.info(
"share of correct parses being scored highest: {:.2%}".format(
pos_best_scored / total_tests
)
)
if at_least_one_failed:
raise Exception("ctparse corpus has errors")
return Xs, ys
================================================
FILE: ctparse/count_vectorizer.py
================================================
from collections import defaultdict
from typing import Dict, Sequence, Tuple, Optional
class CountVectorizer:
def __init__(self, ngram_range: Tuple[int, int]):
"""Create new count vectorizer that also counts n-grams.
A count vectorizer builds an internal vocabulary and embeds each input
by counting for each term in the document how often it appearsin the vocabulary.
Here also n-grams are considered to be part of the vocabulary and the document
terms, respectively
Parameters
----------
ngram_range : Tuple[int, int]
n-gram range to consider
"""
self.ngram_range = ngram_range
self.vocabulary: Optional[Dict[str, int]] = None
@staticmethod
def _create_ngrams(
ngram_range: Tuple[int, int], documents: Sequence[Sequence[str]]
) -> Sequence[Sequence[str]]:
"""For each document in documents, replace original tokens by a list of
all min_n:max_n = self.ngram_range ngrams in that document.
Parameters
----------
ngram_range : Tuple[int, int]
Min and max number of ngrams to generate
documents : Sequence[Sequence[str]]
A sequence of already tokenized documents
Returns
-------
Sequence[Sequence[str]]
For each document all ngrams of tokens in the desired range
"""
min_n, max_n = ngram_range
space_join = " ".join
def _create(document: Sequence[str]) -> Sequence[str]:
doc_len = len(document)
doc_max_n = min(max_n, doc_len) + 1
if min_n == 1:
ngrams = list(document)
min_nn = min_n + 1
else:
ngrams = []
min_nn = min_n
for n in range(min_nn, doc_max_n):
for i in range(0, doc_len - n + 1):
ngrams.append(space_join(document[i : i + n]))
return ngrams
return [_create(d) for d in documents]
@staticmethod
def _get_feature_counts(
ngram_range: Tuple[int, int], documents: Sequence[Sequence[str]]
) -> Sequence[Dict[str, int]]:
"""Count (ngram) features appearing in each document
Parameters
----------
ngram_range : Tuple[int, int]
Min and max number of ngrams to generate
documents : Sequence[Sequence[str]]
Sequence of documents tokenized as sequence of string
Returns
-------
Tuple[Sequence[Dict[str, int]], Set[str]]
For each document a dictionary counting how often which feature appeared and
a set of all features in all documents. Features are according to this
vectorizers n-gram settings.
"""
documents = CountVectorizer._create_ngrams(ngram_range, documents)
count_matrix = []
for document in documents:
# This is 5x faster than using a build in Counter
feature_counts: Dict[str, int] = defaultdict(int)
for feature in document:
feature_counts[feature] += 1
count_matrix.append(feature_counts)
return count_matrix
@staticmethod
def _build_vocabulary(count_matrix: Sequence[Dict[str, int]]) -> Dict[str, int]:
"""Build the vocabulary from feature counts
Parameters
----------
count_matrix : Sequence[Dict[str, int]]
Sequence of dicts with counts (values) per feature (keys)
Returns
-------
Dict[str, int]
The vocabulary as {feature: index} pairs
"""
all_features = set()
for feature_counts in count_matrix:
for feature in feature_counts.keys():
all_features.add(feature)
return {word: idx for idx, word in enumerate(sorted(all_features))}
@staticmethod
def _create_feature_matrix(
vocabulary: Dict[str, int], count_matrix: Sequence[Dict[str, int]]
) -> Sequence[Dict[int, int]]:
"""Map counts of string features to numerical data (sparse maps of
`{feature_index: count}`). Here `feature_index` is relative to the vocabulary of
this vectorizer.
Parameters
----------
vocabulary : Dict[str, int]
Vocabulary with {feature: index} mappings
count_matrix : Sequence[Dict[str, int]]
Sequence of dictionaries with feature counts
Returns
-------
Sequence[Dict[int, int]]
For each document a mapping of `feature_index` to a count how often this
feature appeared in the document.
"""
len_vocab = len(vocabulary)
count_vectors_matrix = []
# Build document frequency matrix
for count_dict in count_matrix:
doc_vector: Dict[int, int] = defaultdict(int)
for word, cnt in count_dict.items():
idx = vocabulary.get(word, None)
if idx is not None:
doc_vector[idx] = cnt
count_vectors_matrix.append(doc_vector)
# add vocab length in first element
count_vectors_matrix[0][len_vocab - 1] = count_vectors_matrix[0][len_vocab - 1]
return count_vectors_matrix
def fit(self, documents: Sequence[Sequence[str]]) -> "CountVectorizer":
"""Learn a vocabulary dictionary of all tokens in the raw documents.
Parameters
----------
documents : Sequence[Sequence[str]]
Sequence of documents, each as a sequence of tokens
Returns
-------
CountVectorizer
The updated vectorizer, i.e. this updates the internal vocabulary
"""
self.fit_transform(documents)
return self
def fit_transform(
self, documents: Sequence[Sequence[str]]
) -> Sequence[Dict[int, int]]:
"""Learn the vocabulary dictionary and return a term-document matrix. Updates
the internal vocabulary state of the vectorizer.
Parameters
----------
documents : Sequence[Sequence[str]
Sequence of documents, each as a sequence of tokens
Returns
-------
Sequence[Dict[int, int]]
Document-term matrix.
"""
count_matrix = CountVectorizer._get_feature_counts(self.ngram_range, documents)
self.vocabulary = CountVectorizer._build_vocabulary(count_matrix)
return CountVectorizer._create_feature_matrix(self.vocabulary, count_matrix)
def transform(self, documents: Sequence[Sequence[str]]) -> Sequence[Dict[int, int]]:
"""Create term-document matrix based on pre-generated vocabulary. Does *not*
update the internal state of the vocabulary.
Parameters
----------
documents : Sequence[Sequence[str]]
Sequence of documents, each as a sequence of tokens
Returns
-------
Sequence[Dict[int, int]]
Document-term matrix.
"""
if not self.vocabulary:
raise ValueError("no vocabulary - vectorizer not fitted?")
count_matrix = CountVectorizer._get_feature_counts(self.ngram_range, documents)
return CountVectorizer._create_feature_matrix(self.vocabulary, count_matrix)
================================================
FILE: ctparse/ctparse.py
================================================
from ctparse.time.postprocess_latent import apply_postprocessing_rules
import logging
from datetime import datetime
from typing import (
cast,
Callable,
Dict,
Iterator,
List,
Optional,
Sequence,
Tuple,
Union,
)
import re
import regex
from itertools import chain
from .partial_parse import PartialParse
from .rule import _regex as global_regex, eu_regex, us_regex
from .scorer import Scorer
from .timers import CTParseTimeoutError, timeit
# Avoid collision with variable "timeout"
from .timers import timeout as timeout_
from .types import Artifact, RegexMatch
from .loader import load_default_scorer
logger = logging.getLogger(__name__)
_DEFAULT_SCORER = load_default_scorer()
class CTParse:
def __init__(
self,
resolution: Artifact,
production: Tuple[Union[int, str], ...],
score: float,
subject: str,
# labels: str,
) -> None:
"""A possible parse returned by ctparse.
:param resolution: the parsed `Time`, `Interval` or `Duration`
:param production: the sequence of rules (productions) used to arrive
at the parse
:param score: a numerical score used to rank parses. A high score means
a more likely parse
"""
self.resolution = resolution
self.production = production
self.score = score
self.subject = subject
# self.labels = labels
def __repr__(self) -> str:
return "CTParse({}, {}, {}, {})".format(
self.resolution, self.production, self.score, self.subject) #self.labels
def __str__(self) -> str:
return "{} s={:.3f} p={} sb={}".format(self.resolution, self.score, self.production, self.subject)
#self.labels)
def ctparse(
txt: str,
ts: Optional[datetime] = None,
pm_bias: Optional[bool] = True,
date_format: Optional[str] = None,
fallback: Optional[bool] = False,
timeout: Union[int, float] = 1.0,
debug: bool = False,
relative_match_len: float = 1.0,
max_stack_depth: int = 10,
scorer: Optional[Scorer] = None,
latent_time: bool = True,
) -> Optional[CTParse]:
"""Parse a string *txt* into a time expression
:param ts: reference time
:type ts: datetime.datetime
:param pm_bias: pm bias on or off / 24h or 12h format
:param date_format: us / eu date format
:param fallback: fallback option if default date format is not parsed
:param timeout: timeout for parsing in seconds; timeout=0
indicates no timeout
:type timeout: float
:param debug: if True do return iterator over all resolution, else
return highest scoring one (default=False)
:param relative_match_len: relative minimum share of
characters an initial regex match sequence must
cover compared to the longest such sequence found
to be considered for productions (default=1.0)
:type relative_match_len: float
:param max_stack_depth: limit the maximal number of highest scored candidate
productions considered for future productions
(default=10); set to 0 to not limit
:type max_stack_depth: int
:param latent_time: if True, resolve expressions that contain only a time
(e.g. 8:00 pm) to be the next matching time after
reference time *ts*
:returns: Optional[CTParse]
"""
parsed = ctparse_gen(
txt,
ts,
pm_bias,
date_format,
fallback,
timeout=timeout,
relative_match_len=relative_match_len,
max_stack_depth=max_stack_depth,
scorer=scorer,
latent_time=latent_time,
)
# TODO: keep debug for back-compatibility, but remove it later
if debug:
return parsed # type: ignore
else:
parsed_list = list(parsed)
# TODO: this way of testing a failure to find a match is a bit clunky with types
if len(parsed_list) == 0 or (len(parsed_list) == 1 and parsed_list[0] is None):
# logger.warning('Failed to produce result for "{}"'.format(txt))
# labels = _get_labels(txt)
txt = re.sub('#[a-zA-Z0-9\-_:/.]+', '', txt).strip()
subject = txt
return CTParse(None, None, None, subject)# labels)
parsed_list.sort(key=lambda p: p.score) # type: ignore
return parsed_list[-1]
def ctparse_gen(
txt: str,
ts: Optional[datetime] = None,
pm_bias: Optional[bool] = True,
date_format: Optional[str] = None,
fallback: Optional[bool] = False,
timeout: Union[int, float] = 1.0,
relative_match_len: float = 1.0,
max_stack_depth: int = 10,
scorer: Optional[Scorer] = None,
latent_time: bool = True,
) -> Iterator[Optional[CTParse]]:
"""Generate parses for the string *txt*.
This function is equivalent to ctparse, with the exception that it returns an
iterator over the matches as soon as they are produced.
"""
if scorer is None:
scorer = _DEFAULT_SCORER
if ts is None:
ts = datetime.now()
generated_parse = list(_ctparse(
_preprocess_string(txt),
ts,
pm_bias,
date_format,
timeout=timeout,
relative_match_len=relative_match_len,
max_stack_depth=max_stack_depth,
scorer=scorer,
))
if fallback and not generated_parse:
if date_format == "US":
fallback_date_format = "EU"
else:
fallback_date_format = "US"
for parse in _ctparse(
_preprocess_string(txt),
ts,
pm_bias,
date_format=fallback_date_format,
timeout=timeout,
relative_match_len=relative_match_len,
max_stack_depth=max_stack_depth,
scorer=scorer,
):
if parse and latent_time:
# NOTE: we post-process after scoring because the model has been trained
# without using the latent time. This means also that the post processing
# step won't be added to the rules
prod = apply_postprocessing_rules(ts, parse.resolution)
parse.resolution = prod
yield parse
else:
for parse in generated_parse:
if parse and latent_time:
# NOTE: we post-process after scoring because the model has been trained
# without using the latent time. This means also that the post processing
# step won't be added to the rules
prod = apply_postprocessing_rules(ts, parse.resolution)
parse.resolution = prod
yield parse
# for parse in _ctparse(
# _preprocess_string(txt),
# ts,
# pm_bias,
# date_format,
# timeout=timeout,
# relative_match_len=relative_match_len,
# max_stack_depth=max_stack_depth,
# scorer=scorer,
# ):
# if parse and latent_time:
# # NOTE: we post-process after scoring because the model has been trained
# # without using the latent time. This means also that the post processing
# # step won't be added to the rules
# prod = apply_postprocessing_rules(ts, parse.resolution)
# parse.resolution = prod
#
# yield parse
def _ctparse(
txt: str,
ts: datetime,
pm_bias: bool,
date_format: str,
timeout: float,
relative_match_len: float,
max_stack_depth: int,
scorer: Scorer,
) -> Iterator[Optional[CTParse]]:
t_fun = timeout_(timeout)
try:
# =========== Label extraction ===========
# labels = _get_labels(txt)
# clear raw text of labels so what follows works properly
# txt = re.sub('#[a-zA-Z0-9\-_:/.]+','', txt).strip()
logger.debug("=" * 80)
logger.debug("-> matching regular expressions")
scope_regex = {**global_regex, **us_regex} if date_format == 'US' else {**global_regex, **eu_regex}
p, _tp = timeit(_match_regex)(txt, scope_regex)
logger.debug("time in _match_regex: {:.0f}ms".format(1000 * _tp))
logger.debug("=" * 80)
logger.debug("-> building initial stack")
regex_stack, _ts = timeit(_regex_stack)(txt, p, t_fun)
logger.debug("time in _regex_stack: {:.0f}ms".format(1000 * _ts))
# add empty production path + counter of contained regex
stack = [PartialParse.from_regex_matches(s) for s in regex_stack]
# TODO: the score should be kept separate from the partial parse
# because it depends also on the text and the ts. A good idea is
# to create a namedtuple of kind StackElement(partial_parse, score)
for pp in stack:
pp.score = scorer.score(txt, ts, pp)
logger.debug("initial stack length: {}".format(len(stack)))
# sort stack by length of covered string and - if that is equal - score
# --> last element is longest coverage and highest scored
stack.sort()
# only keep initial stack elements that cover at least
# relative_match_len characters of what the highest
# scored/covering stack element does cover
stack = [
s
for s in stack
if s.max_covered_chars >= stack[-1].max_covered_chars * relative_match_len
]
logger.debug("stack length after relative match length: {}".format(len(stack)))
# limit depth of stack
stack = stack[-max_stack_depth:]
logger.debug("stack length after max stack depth limit: {}".format(len(stack)))
# ======================== SUBJECT-EXTRACTION ========================
# get subject by extracting regex stack from raw text
regex_matches = [match.prod for match in stack]
regex_matches = [product.match.captures() for tuple in regex_matches for product in tuple]
regex_matches = [match.split() for i in regex_matches for match in i]
regex_matches = list(chain.from_iterable(regex_matches))
# "acr-11" edge case
s = re.search(r'\b[A-Za-z]+\b-\d+[A-Za-z]*', txt)
if s:
raw = re.split(r'[\s]+', txt)
else:
raw = re.split(r'[\s-]+', txt)
# subject = list(set(raw) - set(matches)) # doesn't preserve order, but more efficient
subject = [i for i in raw if i not in regex_matches]
subject = ' '.join(subject)
# remove subject from txt so there's no FP parse
if subject and subject in txt:
txt = subject.replace(txt, '')
# reset stack if txt is 0
if len(txt) == 0:
stack = []
# ===========================================================
# track what has been added to the stack and do not add again
# if the score is not better
stack_prod = {} # type: Dict[Tuple[Artifact, ...], float]
# track what has been emitted and do not emit again
parse_prod = {} # type: Dict[Artifact, float]
while stack:
t_fun()
s = stack.pop()
logger.debug("-" * 80)
logger.debug("producing on {}, score={:.2f}".format(s.prod, s.score))
new_stack_elements = []
for r_name, r in s.applicable_rules.items():
for r_match in _match_rule(s.prod, r[1]):
# apply production part of rule
new_s = s.apply_rule(ts, pm_bias, date_format, r[0], r_name, r_match)
# TODO: We should store scores separately from the production itself
# because the score may depend on the text and the ts
if new_s is not None:
new_s.score = scorer.score(txt, ts, new_s)
if (
new_s
and stack_prod.get(new_s.prod, new_s.score - 1) < new_s.score
):
# either new_s.prod has never been produced
# before or the score of new_s is higher than
# a previous identical production
new_stack_elements.append(new_s)
logger.debug(
" {} -> {}, score={:.2f}".format(
r_name, new_s.prod, new_s.score
)
)
stack_prod[new_s.prod] = new_s.score
if not new_stack_elements:
logger.debug("~" * 80)
logger.debug("no rules applicable: emitting")
# no new productions were generated from this stack element.
# emit all (probably partial) production
for x in s.prod:
if not isinstance(x, RegexMatch):
# TODO: why do we have a different method for scoring
# final productions? This is because you may have non-reducible
# parses of the kind [Time, RegexMatch, Interval] or
# [Time, Time] etc. In this case we want to emit those Time,
# Interval parses separately and score them appropriately
# (the default Scorer.score function only operates on the
# whole PartialParse).
score_x = scorer.score_final(txt, ts, s, x)
# only emit productions not emitted before or
# productions emitted before but scored higher
if parse_prod.get(x, score_x - 1) < score_x:
parse_prod[x] = score_x
logger.debug(
" => {}, score={:.2f}, ".format(x.__repr__(), score_x)
)
yield CTParse(x, s.rules, score_x, subject)#, labels)
else:
# new productions generated, put on stack and sort
# stack by highst score
stack.extend(new_stack_elements)
stack.sort()
stack = stack[-max_stack_depth:]
logger.debug(
"added {} new stack elements, depth after trunc: {}".format(
len(new_stack_elements), len(stack)
)
)
except CTParseTimeoutError:
logger.debug('Timeout on "{}"'.format(txt))
return
# replace all comma, semicolon, whitespace, invisible control, opening and
# closing brackets
# _repl1 = regex.compile(r"[,;\pZ\pC\p{Ps}\p{Pe}]+", regex.VERSION1) # original regex
_repl1 = regex.compile(r"[\pZ\pC]+", regex.VERSION1) # allow brackets
_repl2 = regex.compile(r"(\p{Pd}|[\u2010-\u2015]|\u2043)+", regex.VERSION1)
def _get_labels(txt: str) -> str:
labels = re.findall('#[a-zA-Z0-9\-_:/.]+', txt)
labels = [label.replace("#", "") for label in labels]
return labels
def _preprocess_string(txt: str) -> str:
return cast(
str, _repl2.sub("-", _repl1.sub(" ", txt, concurrent=True).strip()).strip()
)
def _match_rule(
seq: Sequence[Artifact], rule: Sequence[Callable[[Artifact], bool]]
) -> Iterator[Tuple[int, int]]:
if not seq:
return
if not rule:
return
i_r = 0
i_s = 0
r_len = len(rule)
s_len = len(seq)
while i_s < s_len:
if rule[0](seq[i_s]):
i_start = i_s + 1
i_r = 1
while i_start < s_len and i_r < r_len and rule[i_r](seq[i_start]):
i_r += 1
i_start += 1
if i_r == r_len:
yield i_s, i_start
i_s += 1
def _match_regex(txt: str, regexes: Dict[int, regex.Regex]) -> List[RegexMatch]:
# Match a collection of regexes in *txt*
#
# The returned RegexMatch objects are sorted by the start of the match
# :param txt: the text to match against
# :param regexes: a collection of regexes name->pattern
# :return: a list of RegexMatch objects ordered my RegexMatch.mstart
matches = {
RegexMatch(name, m)
for name, re in regexes.items()
for m in re.finditer(txt, overlapped=True, concurrent=True)
}
for m in matches:
logger.debug("regex: {}".format(m.__repr__()))
return sorted(matches, key=lambda x: (x.mstart, x.mend))
def _regex_stack(
txt: str,
regex_matches: List[RegexMatch],
on_do_iter: Callable[[], None] = lambda: None,
) -> List[Tuple[RegexMatch, ...]]:
# Group contiguous RegexMatch objects together.
#
# Assumes that regex_matches are sorted by increasing start index. on_do_iter
# is a callback that will be invoked every time the algorithm performs a loop.
#
# Example:
# Say you have the following text, where the regex matches are the
# words between square brackets.
#
# [Tomorrow] I want to go to the movies between [2] [pm] and [5] [pm].
#
# This function will return the matches that are contiguous (excluding space
# characters)
# [Tomorrow]
# [2], [pm]
# [5], [pm]
#
# This also works with overlapping matches.
#
# Algo:
# * initialize an empty stack
#
# * add all sequences of one expression to the stack, excluding
# expressions which can be reached from "earlier" expression
# (i.e. there is no gap between them):
#
# - say A and B have no gap in between and all sequences starting
# at A have already been produced. These by definition(which?: -) include as
# sub-sequences all sequences starting at B. Any other sequences starting
# at B directly will not add valid variations, as each of them could be
# prefixed with a sequence starting at A
#
# * while the stack is not empty:
#
# * get top sequence s from stack
#
# * generate all possible continuations for this sequence,
# i.e. sequences where expression can be appended to the last
# element s[-1] in s and put these extended sequences on the stack
#
# * if no new continuation could be generated for s, this sequence of
# RegexMatch is appended to the list of results.
prods = []
n_rm = len(regex_matches)
# Calculate the upper triangle of an n_rm x n_rm matrix M where
# M[i, j] == 1 (for i<j) iff the expressions i and j are
# consecutive (i.e. there is no gap and they can be put together
# in one sequence).
# import numpy as np
# M = np.zeros(shape=(n_rm, n_rm), dtype=int)
# --> avoid use of numpy here; since we need column sums below,
# --> the representation of M is columns major, i.e. M[i] is the i-th
# --> column; M[i, j] then basically becomes M[j][i]
M = [[0 for _ in range(n_rm)] for _ in range(n_rm)]
_separator_regex = regex.compile(r"\s*", regex.VERSION1)
def get_m_dist(m1: RegexMatch, m2: RegexMatch) -> int:
# 1 if there is no relevant gap between m1 and m2, 0 otherwise
# assumes that m1 and m2 are sorted be their start index
if m2.mstart < m1.mend:
return 0 # Overlap
gap_match = _separator_regex.fullmatch(txt[m1.mend : m2.mstart])
if gap_match:
return 1 # No Gap
else:
return 0 # Gap
for i in range(n_rm):
for j in range(i + 1, n_rm):
M[j][i] = get_m_dist(regex_matches[i], regex_matches[j])
# NOTE(glanaro): I believe this means that this is a beginning node.
# why reversed?
stack = [
(i,) for i in reversed(range(n_rm)) if sum(M[i]) == 0
] # type: List[Tuple[int, ...]]
while stack:
on_do_iter()
s = stack.pop()
i = s[-1]
new_prod = False
for j in range(i + 1, n_rm):
if M[j][i] == 1:
stack.append(s + (j,))
new_prod = True
if not new_prod:
prod = tuple(regex_matches[i] for i in s)
logger.debug("regex stack {}".format(prod))
prods.append(prod)
return prods
================================================
FILE: ctparse/loader.py
================================================
"""Utility to load default model in ctparse"""
import bz2
import logging
import os
import pickle
from .scorer import Scorer, DummyScorer
from .nb_scorer import NaiveBayesScorer
logger = logging.getLogger(__name__)
# Location of the default model, included with ctparse
DEFAULT_MODEL_FILE = os.path.join(os.path.dirname(__file__), "models", "model.pbz")
def load_default_scorer() -> Scorer:
resource = 'model.pbz'
path = os.path.join(os.path.dirname(__file__), resource)
# logger.warning(path)
# debug
# logger.warning([x.name for x in pkgutil.walk_packages()])
# for exec usage
if os.access(path, mode=os.F_OK):
# d = os.path.dirname(sys.modules[package].__file__)
# logger.warning(os.path.join(d, resource))
with bz2.open(path, 'rb') as f:
# logger.warning(str(f))
mdl = pickle.load(f)
return NaiveBayesScorer(mdl)
# for non-exec usage
elif os.path.exists(DEFAULT_MODEL_FILE):
logger.info("Loading model from {} for non-exec usage".format(DEFAULT_MODEL_FILE))
with bz2.open(DEFAULT_MODEL_FILE, "rb") as fd:
mdl = pickle.load(fd)
return NaiveBayesScorer(mdl)
else:
logger.warning("No model found, initializing empty scorer")
return DummyScorer()
================================================
FILE: ctparse/models/__init__.py
================================================
from .dummy import model_package_init
================================================
FILE: ctparse/models/dummy.py
================================================
def model_package_init():
return 1 == 1
================================================
FILE: ctparse/nb_estimator.py
================================================
from typing import Sequence, Dict, Tuple, List
from math import log, exp
def _log_sum_exp(x: Sequence[float]) -> float:
max_value = max(x)
sum_of_exp = sum(exp(x_i - max_value) for x_i in x)
return max_value + log(sum_of_exp)
class MultinomialNaiveBayes:
"""Implements a multinomial naive Bayes classifier. For background information
(and what has inspired this, see e.g. https://scikit-learn.org/stable/...
...modules/generated/sklearn.naive_bayes.MultinomialNB.html)
"""
def __init__(self, alpha: float = 1.0):
"""Create new un-trained model
Parameters
----------
alpha : Optional[float]
Additive (Laplace/Lidstone) smoothing parameter (0 for no smoothing),
defaults to 1.0
"""
self.alpha = alpha
self.class_prior = (0.0, 0.0)
self.log_likelihood: Dict[str, List[float]] = {}
@staticmethod
def _construct_log_class_prior(y: Sequence[int]) -> Tuple[float, float]:
# Input classes are -1 and 1
neg_class_count = sum(1 if y_i == -1 else 0 for y_i in y)
pos_class_count = len(y) - neg_class_count
neg_log_prior = log(neg_class_count / (pos_class_count + neg_class_count))
pos_log_prior = log(pos_class_count / (pos_class_count + neg_class_count))
return (neg_log_prior, pos_log_prior)
@staticmethod
def _construct_log_likelihood(
X: Sequence[Dict[int, int]], y: Sequence[int], alpha: float
) -> Dict[str, List[float]]:
# Token counts
# implicit assumption from vectorizer: first element has count for #vocab
# size set
vocabulary_len = max(X[0].keys()) + 1
token_counts_negative = [alpha] * vocabulary_len
token_counts_positive = [alpha] * vocabulary_len
for x, y_ in zip(X, y):
for idx, cnt in x.items():
if y_ == 1:
token_counts_positive[idx] += cnt
else:
token_counts_negative[idx] += cnt
token_pos_class_sum = sum(token_counts_positive)
token_neg_class_sum = sum(token_counts_negative)
log_likelihood_negative = []
log_likelihood_positive = []
for token_ind in range(vocabulary_len):
log_likelihood_positive.append(
log(token_counts_positive[token_ind]) - log(token_pos_class_sum)
)
log_likelihood_negative.append(
log(token_counts_negative[token_ind]) - log(token_neg_class_sum)
)
return {
"negative_class": log_likelihood_negative,
"positive_class": log_likelihood_positive,
}
def fit(
self, X: Sequence[Dict[int, int]], y: Sequence[int]
) -> "MultinomialNaiveBayes":
"""Fit a naive Bayes model from a count of feature matrix
Parameters
----------
X : Sequence[Dict[int, int]]
Sequence of sparse {feature_index: count} dictionaries
y : Sequence[int]
Labels +1/-1
Returns
-------
MultinomialNaiveBayes
The fitted model
"""
self.class_prior = self._construct_log_class_prior(y)
self.log_likelihood = self._construct_log_likelihood(X, y, self.alpha)
return self
def predict_log_probability(
self, X: Sequence[Dict[int, int]]
) -> Sequence[Tuple[float, float]]:
"""Calculate the posterior log probability of new sample X
Parameters
----------
X : Sequence[Dict[int, int]]
Sequence of data to predict on as sparse {feature_index: count} dictionarie
Returns
-------
Sequence[Tuple[float, float]]
Tuple of (negative-class, positive-class) log likelihoods
"""
scores = []
for x in X:
# Initialise the scores with priors of positive and negative class
neg_score = self.class_prior[0]
pos_score = self.class_prior[1]
for idx, cnt in x.items():
pos_score += self.log_likelihood["positive_class"][idx] * cnt
neg_score += self.log_likelihood["negative_class"][idx] * cnt
joint_log_likelihood = [neg_score, pos_score]
# Normalize the scores
log_prob_x = _log_sum_exp(joint_log_likelihood)
scores.append((neg_score - log_prob_x, pos_score - log_prob_x))
return scores
================================================
FILE: ctparse/nb_scorer.py
================================================
"""This module cointains the implementation of the scorer based on naive bayes."""
import bz2
import math
import pickle
from datetime import datetime
from typing import Sequence
from ctparse.nb_estimator import MultinomialNaiveBayes
from ctparse.count_vectorizer import CountVectorizer
from ctparse.pipeline import CTParsePipeline
from .scorer import Scorer
from .partial_parse import PartialParse
from .types import Artifact
class NaiveBayesScorer(Scorer):
def __init__(self, nb_model: CTParsePipeline) -> None:
"""Scorer based on a naive bayes estimator.
This scorer models the probability of having a correct parse, conditioned
on the sequence of rules (expressed as a categorical feature) that led to
that parse.
The score is also modified by a "length" factor that penalizes parses that
cover a smaller part of the text string.
:param nb_model:
A scikit-learn style Estimator that was trained on a corpus that takes
a Sequence[Sequence[str]] as X (each entry is a sequence of rule
identifiers) and a Sequence[int] in the set {-1, 1} that indicates if
the parse was correct or incorrect.
"""
self._model = nb_model
@classmethod
def from_model_file(cls, fname: str) -> "NaiveBayesScorer":
with bz2.open(fname, "rb") as fd:
return cls(pickle.load(fd))
def score(self, txt: str, ts: datetime, partial_parse: PartialParse) -> float:
# Penalty for partial matches
max_covered_chars = partial_parse.prod[-1].mend - partial_parse.prod[0].mstart
len_score = math.log(max_covered_chars / len(txt))
X = _feature_extractor(txt, ts, partial_parse)
pred = self._model.predict_log_proba([X])
# NOTE: the prediction is log-odds, or logit
model_score = pred[0][1] - pred[0][0]
return model_score + len_score
def score_final(
self, txt: str, ts: datetime, partial_parse: PartialParse, prod: Artifact
) -> float:
# The difference between the original score and final score is that in the
# final score, the len_score is calculated based on the length of the final
# production
len_score = math.log(len(prod) / len(txt))
X = _feature_extractor(txt, ts, partial_parse)
pred = self._model.predict_log_proba([X])
# NOTE: the prediction is log-odds, or logit
model_score = pred[0][1] - pred[0][0]
# We want the len_score to always take precedence. I believe a logit won't go up
# more than 1000. A better way would be to return an ordering tuple instead,
# but then we would need to change many interfaces.
return model_score + 1000 * len_score
def _feature_extractor(
txt: str, ts: datetime, partial_parse: PartialParse
) -> Sequence[str]:
return [str(r) for r in partial_parse.rules]
def train_naive_bayes(X: Sequence[Sequence[str]], y: Sequence[bool]) -> CTParsePipeline:
"""Train a naive bayes model for NaiveBayesScorer"""
y_binary = [1 if y_i else -1 for y_i in y]
# Create and train the pipeline
pipeline = CTParsePipeline(
CountVectorizer(ngram_range=(1, 3)), MultinomialNaiveBayes(alpha=1.0)
)
model = pipeline.fit(X, y_binary)
return model
def save_naive_bayes(model: CTParsePipeline, fname: str) -> None:
"""Save a naive bayes model for NaiveBayesScorer"""
# TODO: version this model and dump metadata with lots of information
with bz2.open(fname, "wb") as fd:
pickle.dump(model, fd)
================================================
FILE: ctparse/partial_parse.py
================================================
import logging
from datetime import datetime
from typing import (
Callable,
Optional,
Sequence,
Tuple,
TypeVar,
Union,
Dict,
List,
Generator,
)
from .rule import rules as global_rules, ProductionRule, Predicate
from .timers import timeit
from .types import Artifact, RegexMatch
logger = logging.getLogger(__name__)
T = TypeVar("T")
class PartialParse:
def __init__(
self, prod: Tuple[Artifact, ...], rules: Tuple[Union[int, str], ...]
) -> None:
"""A data structure representing a partial parse.
* prod: the current partial production
* rules: the sequence of regular expressions and rules used/applied to produce
prod
* score: the score assigned to this production
"""
if len(prod) < 1:
raise ValueError("prod should have at least one element")
self.prod = prod
self.rules = rules
self.applicable_rules = global_rules
self.max_covered_chars = self.prod[-1].mend - self.prod[0].mstart
self.score = 0.0
@classmethod
def from_regex_matches(
cls, regex_matches: Tuple[RegexMatch, ...]
) -> "PartialParse":
"""Create partial production from a series of RegexMatch
This usually is called when no production rules (with the exception of
regex matches) have been applied.
"""
se = cls(prod=regex_matches, rules=tuple(r.id for r in regex_matches))
logger.debug("=" * 80)
logger.debug("-> checking rule applicability")
# Reducing rules to only those applicable has no effect for
# small stacks, but on larger there is a 10-20% speed
# improvement
se.applicable_rules, _ts = timeit(se._filter_rules)(global_rules)
logger.debug(
"of {} total rules {} are applicable in {}".format(
len(global_rules), len(se.applicable_rules), se.prod
)
)
logger.debug("time in _filter_rules: {:.0f}ms".format(1000 * _ts))
logger.debug("=" * 80)
return se
def apply_rule(
self,
ts: datetime,
pm_bias: bool,
date_format: str,
rule: ProductionRule,
rule_name: Union[str, int],
match: Tuple[int, int],
) -> Optional["PartialParse"]:
"""Check whether the production in rule can be applied to this stack
element.
If yes, return a copy where this update is
incorporated in the production, the record of applied rules
and the score.
:param ts: reference time
:param pm_bias: bias option bool
:param date_format: us / eu date format
:param rule: a tuple where the first element is the production rule to apply
:param rule_name: the name of the rule
:param match: the start and end index of the parameters that the rule needs.
"""
prod = rule(ts, pm_bias, date_format, *self.prod[match[0]: match[1]])
if prod is not None:
pp = PartialParse(
prod=self.prod[: match[0]] + (prod,) + self.prod[match[1] :],
rules=self.rules + (rule_name,),
)
pp.applicable_rules = self.applicable_rules
return pp
else:
return None
def __lt__(self, other: "PartialParse") -> bool:
"""Sort stack elements by (a) the length of text they can
(potentially) cover and (b) the score assigned to the
production.
a < b <=> a.max_covered_chars < b.max_covered_chars or
(a.max_covered_chars <= b.max_covered_chars and a.score < b.score)
"""
return (self.max_covered_chars < other.max_covered_chars) or (
self.max_covered_chars == other.max_covered_chars
and self.score < other.score
)
def __repr__(self) -> str:
return "PartialParse(prod={}, rules={}, score={})".format(
repr(self.prod), repr(self.rules), repr(self.score)
)
def _filter_rules(
self, rules: Dict[str, Tuple[ProductionRule, List[Predicate]]]
) -> Dict[str, Tuple[ProductionRule, List[Predicate]]]:
# find all rules that can be applied to the current prod sequence
def _hasNext(it: Generator[List[int], None, None]) -> bool:
try:
next(it)
return True
except StopIteration:
return False
return {
rule_name: r
for rule_name, r in rules.items()
if _hasNext(_seq_match(self.prod, r[1]))
}
def _seq_match(
seq: Sequence[T], pat: Sequence[Callable[[T], bool]], offset: int = 0
) -> Generator[List[int], None, None]:
# :param seq: a list of intermediate productions, either of type
# RegexMatch or some other Artifact
#
# :param pat: a list of rule patterns to be matched, i.e. either a
# RegexMatch or a callable
#
# Determine whether the pattern pat matches the sequence seq and
# return a list of lists, where each sub-list contains those
# indices where the RegexMatch objects in pat are located in seq.
#
# A pattern pat only matches seq, iff each RegexMatch in pat is in
# seq in the same order and iff between two RegexMatches aligned
# to seq there is at least one additional element in seq. Reason:
#
# * Rule patterns never have two consequitive RegexMatch objects.
#
# * Hence there must be some predicate/dimension between two
# * RegexMatch objects.
#
# * For the whole pat to match there must then be at least one
# element in seq that can product this intermediate bit
#
# If pat does not start with a RegexMatch then there must be at
# least one element in seq before the first RegexMatch in pat that
# is alignes on seq. Likewise, if pat does not end with a
# RegexMatch, then there must be at least one additional element
# in seq to match the last non-RegexMatch element in pat.
#
# STRONG ASSUMPTIONS ON ARGUMENTS: seq and pat do not contain
# consequiteve elements which are both of type RegexMatch! Callers
# obligation to ensure this!
if not pat:
# if pat is empty yield the empty match
yield []
elif not seq or not pat:
# if either seq or pat is empty there will be no match
return
elif pat[-1].__name__ != "_regex_match":
# there must be at least one additional element in seq at the
# end
yield from _seq_match(seq[:-1], pat[:-1], offset)
elif len(pat) > len(seq):
# if pat is longer than seq it cannot match
return
else:
p1 = pat[0]
# if p1 is not a RegexMatch, then continue on next pat and
# advance sequence by one
if p1.__name__ != "_regex_match":
yield from _seq_match(seq[1:], pat[1:], offset + 1)
else:
# Get number of RegexMatch in p
n_regex = sum(1 for p in pat if p.__name__ == "_regex_match")
# For each occurance of RegexMatch pat[0] in seq
for iseq, s in enumerate(seq):
# apply _regex_match check
if p1(s):
# for each match of pat[1:] in seq[iseq+1:], yield a result
for subm in _seq_match(seq[iseq + 1 :], pat[1:], offset + iseq + 1):
if len(subm) == n_regex - 1:
# only yield if all subsequent RegexMatch
# have been aligned!
yield [iseq + offset] + subm
================================================
FILE: ctparse/pipeline.py
================================================
from typing import Sequence, Tuple
from .nb_estimator import MultinomialNaiveBayes
from .count_vectorizer import CountVectorizer
class CTParsePipeline:
def __init__(self, transformer: CountVectorizer, estimator: MultinomialNaiveBayes):
"""Setup a pipeline of feature extraction and naive bayes. Overkill for what it
does but leaves room to use different models/features in the future
Parameters
----------
transformer : CountVectorizer
feature extraction step
estimator : MultinomialNaiveBayes
naive bayes model
"""
self.transformer = transformer
self.estimator = estimator
def fit(self, X: Sequence[Sequence[str]], y: Sequence[int]) -> "CTParsePipeline":
"""Fit the transformer and then fit the Naive Bayes model on the transformed
data
Returns
-------
CTParsePipeline
Returns the fitted pipeline
"""
X_transformed = self.transformer.fit_transform(X)
self.estimator = self.estimator.fit(X_transformed, y)
return self
def predict_log_proba(
self, X: Sequence[Sequence[str]]
) -> Sequence[Tuple[float, float]]:
"""Apply the transforms and get probability predictions from the estimator
Parameters
----------
X : Sequence[Sequence[str]]
Sequence of documents, each as sequence of tokens. In ctparse case there are
just the names of the regex matches and rules applied
Returns
-------
Sequence[Tuple[float, float]]
For each document the tuple of negative/positive log probability from the
naive bayes model
"""
X_transformed = self.transformer.transform(X)
return self.estimator.predict_log_probability(X_transformed)
================================================
FILE: ctparse/py.typed
================================================
# Marker file for PEP 561.
================================================
FILE: ctparse/rule.py
================================================
# flake8: noqa F405
import logging
from datetime import datetime
from typing import Any, Callable, Dict, List, Optional, Tuple, Union, Type
import regex
from .types import Artifact, RegexMatch
logger = logging.getLogger(__name__)
# A predicate is a callable that returns True if the predicate
# applies to the artifact
Predicate = Callable[[Artifact], bool]
# ProductionRule is a function used to generate an artifact given other
# artifacts.
ProductionRule = Callable[..., Optional[Artifact]]
rules = {} # type: Dict[str, Tuple[ProductionRule, List[Predicate]]]
_regex_cnt = 150 # leave this much space for ids of production types
_regex = {} # compiled regex
_regex_str = {} # map regex id to original string
_str_regex = {} # type: Dict[str, int] # map regex raw str to regex id
eu_regex = {}
us_regex = {}
_regex_hour = r"(?:[01]?\d)|(?:2[0-3])"
_regex_minute = r"[0-5]\d"
_regex_day = r"[012]?[1-9]|10|20|30|31"
_regex_month = r"10|11|12|0?[1-9]"
_regex_year = r"(?:19\d\d)|(?:20[0-2]\d)|(?:\d\d)"
# used in many places in rules
_regex_to_join = (
r"(\-|to( the)?|(un)?til|bis( zum)?|zum|auf( den)?|und|"
"no later than|spätestens?|at latest( at)?|and)"
)
_defines = (
r"(?(DEFINE)(?<_hour>{regex_hour})(?P<_minute>{regex_minute})"
"(?P<_day>{regex_day})(?P<_month>{regex_month})"
"(?P<_year>{regex_year}))"
).format(
regex_hour=_regex_hour,
regex_minute=_regex_minute,
regex_day=_regex_day,
regex_month=_regex_month,
regex_year=_regex_year,
)
def rule(*patterns: Union[str, Predicate], **kwargs) -> Callable[[Any], ProductionRule]:
def _map(p: Union[str, Predicate]) -> Predicate:
if isinstance(p, str):
# its a regex
global _regex_cnt
if p in _str_regex:
# have seen this regex before - recycle
return regex_match(_str_regex[p])
# test the regex first
re = r"{defines}(?i)(?P<R{re_key}>{re})".format(
defines=_defines, re=p, re_key=_regex_cnt
)
new_rr = regex.compile(
# Removed the separator here - leads to more matches,
# as now each rule can also match if it is not followed
# or preceeded by a separator character
# r'(?i)(?:{sep})(?P<{re_key}>{re})(?:{sep})'.format(
re,
regex.VERSION1,
)
if new_rr.match(""):
raise ValueError("expression {} matches empty strings".format(p))
if kwargs and "date_format" in kwargs:
if kwargs['date_format'] == 'US':
us_regex[_regex_cnt] = new_rr
else:
eu_regex[_regex_cnt] = new_rr
else:
_regex[_regex_cnt] = new_rr
_regex_str[_regex_cnt] = p
_str_regex[p] = _regex_cnt
_regex_cnt += 1
return regex_match(_regex_cnt - 1)
else:
return p
# check that in rules we never have a regex followed by a regex -
# that must be merged into one regex
def _has_consequtive_regex(
ps: Tuple[Union[str, Callable[[Artifact], bool]], ...]
) -> bool:
for p0, p1 in zip(ps[:-1], ps[1:]):
if isinstance(p0, str) and isinstance(p1, str):
return True
return False
if _has_consequtive_regex(patterns):
raise ValueError("rule which contains consequtive regular expressions found")
mapped_patterns = [_map(p) for p in patterns]
def fwrapper(f: ProductionRule) -> ProductionRule:
def wrapper(ts: datetime, *args: Artifact) -> Optional[Artifact]:
res = f(ts, *args)
if res is not None:
# upon a successful production, update the span
# information by expanding it to that of all args
res.update_span(*args)
return res
rules[f.__name__] = (wrapper, mapped_patterns)
return wrapper
return fwrapper
def regex_match(r_id: int) -> Predicate:
def _regex_match(r: Artifact) -> bool:
return type(r) == RegexMatch and r.id == r_id # type: ignore
return _regex_match
def dimension(dim: Type[Artifact]) -> Predicate:
def _dimension(d: Artifact) -> bool:
return isinstance(d, dim)
return _dimension
def predicate(pred: str) -> Predicate:
def _predicate(d: Artifact) -> Any:
return getattr(d, pred, False)
return _predicate
from .time.rules import * # noqa
================================================
FILE: ctparse/scorer.py
================================================
"""This module contains the Scorer abstraction that can be used to
implement scoring strategies for ctparse.
"""
from abc import ABCMeta, abstractmethod
from datetime import datetime
from random import Random
from typing import Optional
from .partial_parse import PartialParse
from .types import Artifact
class Scorer(metaclass=ABCMeta):
"""Interface for scoring parses generated by ctparse"""
@abstractmethod
def score(self, txt: str, ts: datetime, partial_parse: PartialParse) -> float:
"""Produce a score for a partial production.
:param txt: the text that is being parsed
:param ts: the reference time
:param partial_parse: the partial parse that needs to be scored
"""
@abstractmethod
def score_final(
self, txt: str, ts: datetime, partial_parse: PartialParse, prod: Artifact
) -> float:
"""Produce the final score for a production.
:param txt: the text that is being parsed
:param ts: the reference time
:param partial_parse: the PartialParse object that generated the production
:param prod: the production
"""
class DummyScorer(Scorer):
"""A scorer that always return a 0.0 score."""
def score(self, txt: str, ts: datetime, partial_parse: PartialParse) -> float:
return 0.0
def score_final(
self, txt: str, ts: datetime, partial_parse: PartialParse, prod: Artifact
) -> float:
return 0.0
class RandomScorer(Scorer):
def __init__(self, rng: Optional[Random] = None) -> None:
"""A score that returns a random number between 0 and 1.
:param rng:
the random number generator to use
"""
self.rng = rng if rng is not None else Random()
def score(self, txt: str, ts: datetime, partial_parse: PartialParse) -> float:
return self.rng.random()
def score_final(
self, txt: str, ts: datetime, partial_parse: PartialParse, prod: Artifact
) -> float:
return self.rng.random()
================================================
FILE: ctparse/time/__init__.py
================================================
================================================
FILE: ctparse/time/auto_corpus.py
================================================
corpus = [ # pragma: no cover
[
"Time[]{2018-01-04 X:X (X/X)}",
"2017-12-20T20:34",
[
"THURSDAY 4th JANUARY 2018",
"04. Januar 2018",
"THURSDAY 4th JANUARY 2018",
"THURSDAY 4th JANUARY 2018",
"04. Januar 2018",
],
],
[
"Interval[]{2017-03-12 18:40 (X/X) - 2017-03-12 19:45 (X/X)}",
"2017-02-10T10:59",
["Am 12.03.2017 18:40 - 19:45", "Am 12.03.2017 18:40 - 19:45"],
],
[
"Interval[]{X-X-X 10:00 (X/X) - X-X-X 15:00 (X/X)}",
"2022-12-12T09:59",
["10-15", "10-15", "10-15", "10-15", "10-15", "10-15", "10-15", "10-15", "10-15", "10-15", "10-15", "10-15", "10-15", ],
],
[
"Interval[]{2022-12-16 10:00 (X/X) - 2022-12-16 15:00 (X/X)}",
"2022-12-13T09:59",
["friday 10-15", "friday 10-15", "friday 10-15", "friday 10-15", "friday 10-15", "friday 10-15", "friday 10-15", "friday 10-15", "friday 10-15", ],
],
[
"Time[]{2017-05-11 X:X (X/X)}",
"2017-05-09T06:47",
["Thu 11. may 2017", "am 11.", "Thursday 11.05.17", "Thu 11. may 2017"],
],
[
"Interval[]{2016-05-04 20:00 (X/X) - 2016-05-04 21:00 (X/X)}",
"2016-04-06T15:25",
["Mi., 04.05.2016 ca. 08:00 Uhr bis ca. 09:00 Uhr"],
],
[
"Interval[]{2018-02-05 X:X (X/X) - 2018-02-15 X:X (X/X)}",
"2018-01-26T09:32",
["Feb 5-15"],
],
[
"Time[]{2016-05-27 14:00 (X/X)}",
"2016-05-24T04:39",
["Fri 5/27 2:00pm", "Fri 5/27 2:00pm"],
],
["Time[]{2016-05-27 17:20 (X/X)}", "2016-05-24T04:39", ["Fri 5/27 5:20pm"]],
[
"Time[]{2016-06-24 12:40 (X/X)}",
"2016-06-22T09:08",
["Fri 6/24 12:40pm", "Fri 6/24 12:40pm"],
],
[
"Time[]{2016-09-23 20:00 (X/X)}",
"2016-09-06T05:05",
["Fri 9/23 8pm", "Fri 9/23 8pm"],
],
[
"Time[]{2016-10-26 06:30 (X/X)}",
"2016-10-11T08:25",
["Oct 26 morning 6:30am", "Oct 26 morning 6:30am"],
],
[
"Time[]{2018-02-28 X:X (X/X)}",
"2017-12-12T09:33",
["Feb 28, 2018", "Feb 28, 2018", "Feb 28, 2018"],
],
[
"Interval[]{2017-03-01 X:X (X/X) - 2017-03-03 X:X (X/X)}",
"2017-02-24T12:30",
["Vom 01.03. bis 03.03"],
],
[
"Time[]{2017-10-20 X:X (X/X)}",
"2017-09-19T09:42",
["Fri 20th Oct 2017", "Fri 20th Oct 2017", "Fri 20th Oct 2017"],
],
[
"Time[]{2017-02-03 X:X (X/X)}",
"2017-02-01T11:43",
[
"Februar 3, 2017",
"am 3. Februar 2017",
"Februar 3, 2017",
"Februar 3, 2017",
"Freitag 03.02",
"am 3. Februar 2017",
],
],
[
"Time[]{2017-11-02 X:X (X/X)}",
"2017-09-03T11:45",
[
"November 2, 2017",
"November 2, 2017",
"November 2, 2017",
"Thursday 02.11.",
],
],
[
"Interval[]{2017-04-03 X:X (X/X) - 2017-04-04 X:X (X/X)}",
"2017-03-14T08:31",
["April 3-4"],
],
["Time[]{2016-06-05 X:X (X/X)}", "2016-06-02T07:52", ["Sunday 6/5", "Sunday 6/5"]],
["Time[]{2018-04-27 X:X (X/X)}", "2017-12-14T23:57", ["Friday 27"]],
[
"Interval[]{2017-08-21 X:X (X/X) - 2017-08-25 X:X (X/X)}",
"2017-08-08T09:40",
["August 21-25"],
],
[
"Time[]{2018-02-16 X:X (X/X)}",
"2018-01-10T11:14",
["Freitag 16.", "Freitag 16."],
],
[
"Time[]{2017-07-13 X:X (X/X)}",
"2017-07-06T08:05",
["Donnerstag 13. Juli 2017", "Donnerstag 13. Juli 2017"],
],
[
"Time[]{2017-11-10 X:X (X/X)}",
"2017-08-02T06:57",
["Freitag 10.November 2017", "Freitag 10.November 2017"],
],
# [
# "Time[]{2016-01-26 X:X (X/morning)}",
# "2016-01-13T12:05",
# ["Dienstagmorgen 26.1."],
# ],
[
"Time[]{2017-08-17 13:55 (X/X)}",
"2017-08-10T09:11",
["Donnerstag 17.8. 13:55", "Donnerstag 17.8. 13:55", "Donnerstag 17.8. 13:55"],
],
# [
# "Time[]{2017-12-01 X:X (X/afternoon)}",
# "2017-11-07T16:48",
# ["Freitagnachmittag 01.12."],
# ],
# [
# "Time[]{2016-03-08 X:X (X/evening)}",
# "2015-11-19T08:54",
# ["Dienstagabend 08.03.16"],
# ],
# [
# "Time[]{2017-02-07 X:X (X/morning)}",
# "2017-01-13T10:30",
# ["Dienstagmorgen 07.02.17"],
# ],
["Time[]{2016-04-17 X:X (X/X)}", "2016-04-08T11:42", ["Sunday 17th"]],
[
"Time[]{2018-03-24 X:X (X/X)}",
"2018-03-09T15:21",
[
"Saturday 24th March 2018",
"Saturday 24th March 2018",
"Saturday 24th March 2018",
],
],
# [
# "Time[]{2016-05-26 X:X (X/evening)}",
# "2016-05-23T07:31",
# ["Thursday 26th in the evening"],
# ],
# [
# "Time[]{2016-10-19 X:X (X/evening)}",
# "2016-10-11T17:10",
# ["Wednesday 19th evening"],
# ],
# [
# "Time[]{2017-05-12 X:X (X/last)}",
# "2017-05-04T07:31",
# ["Friday 12th last flight"],
# ],
["Time[]{2017-05-08 X:X (X/X)}", "2017-04-27T14:52", ["Monday 8th"]],
[
"Time[]{2018-03-09 X:X (X/X)}",
"2018-02-15T12:21",
[
"Friday 9th March 2018",
"Friday 9th March 2018",
"Friday 9th March 2018",
"am Freitag 09.03",
],
],
[
"Time[]{2017-09-13 X:X (X/X)}",
"2017-09-11T14:17",
["Mittwoch den 13.", "Mittwoch den 13."],
],
[
"Interval[]{2017-08-08 20:05 (X/X) - 2017-08-08 21:00 (X/X)}",
"2017-08-03T11:10",
[
"Dienstag den 08.08.2017 20:05 - 21:00 Uhr",
"Dienstag den 08.08.2017 20:05 - 21:00 Uhr",
"Dienstag den 08.08.2017 20:05 - 21:00 Uhr",
],
],
[
"Time[]{2016-12-22 X:X (X/X)}",
"2016-12-19T21:12",
["Donnerstag diese Woche", "Donnerstag diese Woche", "Donnerstag diese Woche"],
],
# [
# "Time[]{2018-03-26 X:X (X/evening)}",
# "2017-12-15T11:14",
# ["Monday evening 26th March"],
# ],
# [
# "Time[]{2017-06-19 X:X (X/morning)}",
# "2017-05-18T06:53",
# ["Monday morning, 19.6.17"],
# ],
[
"Time[]{2018-03-01 X:X (X/X)}",
"2018-01-10T12:18",
[
"Donnerstag, 1. M\u00e4rz 2018",
"Donnerstag, den 01. M\u00e4rz 2018",
"1/3/2018",
"Donnerstag 01.03.2018",
"Donnerstag, 1. M\u00e4rz 2018",
"Donnerstag, den 01. M\u00e4rz 2018",
],
],
[
"Time[]{2016-04-06 20:20 (X/X)}",
"2016-03-11T11:04",
["Mittwoch, 6.4. 8:20", "Mittwoch, 6.4. 8:20", "Mittwoch, 6.4. 8:20"],
],
[
"Time[]{2016-04-07 15:35 (X/X)}",
"2016-03-11T11:04",
["Donnerstag, 7.4. 15:35", "Donnerstag, 7.4. 15:35", "Donnerstag, 7.4. 15:35"],
],
[
"Time[]{2017-08-08 14:31 (X/X)}",
"2017-08-08T08:28",
["Dienstag, 8.8. 14:31h", "Dienstag, 8.8. 14:31h", "Dienstag, 8.8. 14:31h"],
],
[
"Time[]{2017-06-30 X:X (X/X)}",
"2017-06-23T09:53",
["Freitag, 30. Juni 2017", "Freitag, 30. Juni 2017"],
],
[
"Time[]{2016-11-17 X:X (X/X)}",
"2016-10-20T14:34",
["Donnerstag, 17. November 2016", "Donnerstag, 17. November 2016"],
],
[
"Time[]{2017-11-13 X:X (X/X)}",
"2017-10-24T13:35",
["Montag, 13.11. 2017", "Montag, 13.11. 2017", "Montag, 13.11. 2017"],
],
[
"Interval[]{2016-12-13 17:06 (X/X) - 2016-12-13 20:44 (X/X)}",
"2016-12-08T15:30",
[
"Dienstag, 13.12.2016 um 05:06 - 08:44 Uhr",
"Dienstag, 13.12.2016 um 05:06 - 08:44 Uhr",
"Dienstag, 13.12.2016 um 05:06 - 08:44 Uhr",
],
],
[
"Time[]{2017-12-15 X:X (X/X)}",
"2017-11-15T21:11",
["Friday 15th"],
],
[
"Time[]{2018-03-12 X:X (X/X)}",
"2018-03-02T10:05",
["Monday, 12th of March 2018", "Monday, 12th of March 2018"],
],
# [
# "Time[]{2018-04-03 X:X (X/afternoon)}",
# "2018-03-22T11:25",
# ["Dienstag, den 3. April 2018 nachmittags"],
# ],
[
"Interval[]{2017-10-05 21:00 (X/X) - 2017-10-05 22:00 (X/X)}",
"2017-09-28T07:55",
[
"Donnerstag, den 5.10.2017 09:00 - 10:00 Uhr",
"Donnerstag, den 5.10.2017 09:00 - 10:00 Uhr",
"Donnerstag, den 5.10.2017 09:00 - 10:00 Uhr",
],
],
[
"Time[]{2017-10-10 X:X (X/X)}",
"2017-10-08T16:08",
["Tuesday 10.", "vom 10.", "Tuesday 10."],
],
[
"Time[]{2017-05-22 16:13 (X/X)}",
"2017-05-22T12:32",
["Morgen, den 22. Mai 2017 16:13"],
],
[
"Time[]{2017-10-03 X:X (X/X)}",
"2017-08-28T14:31",
["3 Oct 2017", "3. Oktober 2017", "3 Oct 2017", "3. Oktober 2017"],
],
[
"Time[]{2018-04-06 X:X (X/X)}",
"2018-01-08T07:52",
[
"6 April 2018",
"06.04.2018 17:40 Uhr",
"6 April 2018",
"06.04.2018 17:40 Uhr",
],
],
[
"Interval[]{2017-06-04 X:X (X/X) - 2017-06-06 X:X (X/X)}",
"2017-05-25T18:08",
["4-6.6.", "4-6.6.", "4-6.6."],
],
["Time[]{2017-07-02 X:X (X/X)}", "2017-06-29T06:15", ["2."]],
[
"Time[]{2017-07-04 X:X (X/X)}",
"2017-06-29T06:15",
["4. Juli 2017", "4. Juli 2017"],
],
["Time[]{2017-08-06 23:05 (X/X)}", "2017-07-26T09:21", ["6. August 11:05"]],
[
"Time[]{2016-11-02 X:X (X/X)}",
"2016-10-04T11:39",
["2. November 2016", "2. November 2016"],
],
[
"Time[]{2016-04-03 X:X (X/X)}",
"2015-11-02T11:37",
["3. April 2016", "3. April 2016"],
],
[
"Time[]{2016-11-04 X:X (X/X)}",
"2016-10-04T11:39",
["4. November 2016", "4. November 2016"],
],
[
"Time[]{2017-10-05 X:X (X/X)}",
"2017-07-17T07:46",
["5. Oktober 2017", "5. Oktober 2017"],
],
[
"Time[]{2018-01-06 X:X (X/X)}",
"2017-12-19T09:24",
["6. Januar 2018", "6. Januar 2018"],
],
[
"Interval[]{2017-07-03 21:00 (X/X) - 2017-07-03 22:00 (X/X)}",
"2017-06-26T13:05",
[
"3.7.2017 gegen 9-10 Uhr",
"3.7.2017 gegen 9-10 Uhr",
"3.7.2017 gegen 9-10 Uhr",
],
],
[
"Time[]{2018-10-07 18:10 (X/X)}",
"2018-02-07T13:05",
["5.03. - 07.10. 18:10", "5.03. - 07.10. 18:10"],
],
[
"Time[]{2017-07-01 22:00 (X/X)}",
"2017-06-02T09:41",
["1.07.2017 ca. 10Uhr", "1.07.2017 ca. 10Uhr"],
],
["Time[]{2017-03-17 X:X (X/X)}", "2017-03-03T13:30", ["3/17"]],
["Time[]{2017-02-11 X:X (X/X)}", "2017-01-31T10:12", ["11"]],
["Time[]{2017-01-14 X:X (X/X)}", "2017-01-05T08:07", ["14"]],
["Time[]{2017-11-15 X:X (X/X)}", "2017-11-08T16:14", ["15"]],
["Time[]{2016-09-19 X:X (X/X)}", "2016-08-19T11:23", ["19"]],
["Time[]{2017-04-20 X:X (X/X)}", "2017-04-18T11:04", ["20"]],
[
"Time[]{2017-09-25 X:X (X/X)}",
"2017-09-10T15:46",
["25 SEP 2017,", "25 SEP 2017,"],
],
[
"Time[]{2016-05-17 X:X (X/X)}",
"2016-05-10T10:31",
["17 May 2016", "17 May 2016"],
],
[
"Time[]{2018-02-21 X:X (X/X)}",
"2018-01-17T14:12",
["21 Feb 2018", "21 Feb 2018"],
],
[
"Time[]{2017-10-24 X:X (X/X)}",
"2017-10-17T18:14",
["24 Oct 2017", "24 Oct 2017"],
],
[
"Time[]{2017-04-24 X:X (X/X)}",
"2017-03-09T09:35",
["24 April 17", "24 April 17"],
],
[
"Time[]{2018-01-10 X:X (X/X)}",
"2017-10-03T03:36",
["10 January 2018", "10/01/2018", "10 January 2018", "10.01.2018 15:37"],
],
[
"Time[]{2017-09-10 X:X (X/X)}",
"2017-07-31T07:05",
["10 September 2017", "10 September 2017"],
],
[
"Time[]{2018-04-11 X:X (X/X)}",
"2018-01-08T07:52",
["11 April 2018", "11 April 2018"],
],
[
"Time[]{2017-08-14 X:X (X/X)}",
"2017-07-31T07:05",
["14 August 2017", "14 August 2017"],
],
[
"Time[]{2018-02-15 X:X (X/X)}",
"2018-01-15T08:26",
[
"15 February 2018",
"Thursday 15.02.",
"Do. 15.",
"15 February 2018",
"Thursday 15.02.",
],
],
[
"Time[]{2016-12-21 X:X (X/X)}",
"2016-12-09T12:58",
["21 December 2016", "21 December 2016"],
],
[
"Time[]{2017-12-22 X:X (X/X)}",
"2017-10-03T03:36",
["22 December 2017", "22 December 2017"],
],
[
"Time[]{2016-06-16 06:40 (X/X)}",
"2016-06-16T13:14",
["16 june 6:40 am", "16 june 6:40 am", "16 june 6:40 am"],
],
[
"Interval[]{2017-09-15 15:00 (X/X) - None}",
"2017-09-07T13:55",
["15 after 15:00"],
],
["Time[]{2017-02-21 X:X (X/X)}", "2017-02-06T08:28", ["21-2-2017"]],
["Time[]{2017-02-22 X:X (X/X)}", "2017-02-06T08:28", ["22-2-2017"]],
["Time[]{2017-02-23 X:X (X/X)}", "2017-02-06T08:28", ["23-2-2017"]],
# 19-20 should be hour interval not date
# [
# "Interval[]{2018-03-19 X:X (X/X) - 2018-03-20 X:X (X/X)}",
# "2018-03-06T09:46",
# ["19-20"],
# ],
# ["Time[]{2016-05-28 09:00 (X/X)}", "2016-05-26T06:48", ["28-05 09:00"]],
[
"Interval[]{2017-11-12 X:X (X/X) - 2017-11-13 X:X (X/X)}",
"2017-10-03T08:32",
["12-13 november"],
],
[
"Time[]{2016-10-09 X:X (X/X)}",
"2016-10-07T09:38",
["09-10-16", "09-10-16", "09-10-16"],
],
[
"Time[]{2015-10-25 X:X (X/X)}",
"2015-10-13T12:11",
["15-10-25", "15-10-25", "15-10-25"],
],
[
"Time[]{2016-04-19 X:X (X/X)}",
"2016-04-12T14:27",
["16-04-19", "16-04-19", "Dienstag 19.4.", "16-04-19"],
],
["Time[]{2016-05-31 X:X (X/X)}", "2016-05-26T14:38", ["16-05-31", "16-05-31"]],
["Time[]{2017-08-04 X:X (X/X)}", "2017-07-24T09:18", ["04-08-2017"]],
["Time[]{2016-10-04 X:X (X/X)}", "2016-09-26T13:20", ["04-10-2016"]],
["Time[]{2017-11-05 X:X (X/X)}", "2017-10-18T18:45", ["05-11-2017"]],
[
"Time[]{2018-05-07 X:X (X/X)}",
"2018-03-21T13:20",
["07/05/2018", "on Monday 7th May", "on Monday 7th May"],
],
["Time[]{2016-10-07 X:X (X/X)}", "2016-09-26T13:20", ["07.10.2016"]],
["Time[]{2016-03-08 X:X (X/X)}", "2016-03-07T08:46", ["08/03/2016"]],
["Time[]{2018-05-09 X:X (X/X)}", "2018-03-21T13:20", ["09/05/2018"]],
["Time[]{2017-11-09 X:X (X/X)}", "2017-10-18T18:45", ["09.11.2017"]],
["Time[]{2016-03-10 X:X (X/X)}", "2016-03-07T08:46", ["10.03.2016"]],
["Time[]{2016-12-11 X:X (X/X)}", "2016-12-01T08:24", ["11.12.2016"]],
[
"Time[]{2017-12-11 X:X (X/X)}",
"2017-11-22T13:00",
["11-12-2017", "Montag 11.12"],
],
[
"Time[]{2017-11-12 X:X (X/X)}",
"2017-10-18T18:45",
["12-11-2017", "Sunday 12th November 2017"],
],
["Time[]{2017-01-13 X:X (X/X)}", "2017-11-30T13:54", ["13.01.2017"]],
["Time[]{2017-03-13 X:X (X/X)}", "2017-03-02T13:17", ["13.03.2017"]],
["Time[]{2016-06-01 22:16 (X/X)}", "2016-05-25T09:14", ["01.06.2016 10:16"]],
["Time[]{2016-06-01 16:00 (X/X)}", "2016-05-25T09:14", ["01.06.2016 16:00"]],
["Time[]{2017-11-06 17:00 (X/X)}", "2017-10-23T14:23", ["06.11.2017 17:00"]],
["Time[]{2017-11-08 17:55 (X/X)}", "2017-10-23T14:23", ["08/11/2017 17:55"]],
["Time[]{2018-03-10 19:30 (X/X)}", "2018-02-15T15:23", ["10/03/2018 19:30"]],
["Time[]{2018-03-14 14:35 (X/X)}", "2018-02-15T15:23", ["14/03/2018 14:35"]],
[
"Interval[]{2017-09-11 X:X (X/X) - 2017-09-13 X:X (X/X)}",
"2017-08-21T15:07",
["11-13. September"],
],
[
"Interval[]{2018-04-02 X:X (X/X) - 2018-04-05 X:X (X/X)}",
"2018-03-18T12:16",
["02-05.4", "02-05.4", "02-05.4"],
],
[
"Interval[]{2018-01-10 X:X (X/X) - 2018-01-11 X:X (X/X)}",
"2017-12-30T15:14",
["10-11.1.", "10-11.1.", "10-11.1."],
],
["Time[]{2015-12-02 X:X (X/X)}", "2015-11-16T10:37", ["02."]],
["Time[]{2017-04-03 X:X (X/X)}", "2017-03-08T14:38", ["03.", "03.04. 2017"]],
["Time[]{2017-02-06 X:X (X/X)}", "2017-01-31T19:27", ["06."]],
["Time[]{2017-02-08 X:X (X/X)}", "2017-01-16T15:44", ["08."]],
["Time[]{2010-11-11 X:X (X/X)}", "2017-08-04T15:22", ["11. Nov 2010"]],
[
"Time[]{2017-05-12 X:X (X/X)}",
"2017-05-03T13:19",
["12. Mai 2017", "12. Mai 2017"],
],
["Time[]{2008-02-15 X:X (X/X)}", "2017-08-04T15:22", ["15. Feb 2008"]],
[
"Time[]{2017-05-16 X:X (X/X)}",
"2017-05-08T14:03",
["16. Mai 2017", "16. Mai 2017"],
],
["Time[]{2014-08-17 X:X (X/X)}", "2017-08-04T15:22", ["17. Aug 2014"]],
[
"Time[]{2018-02-26 X:X (X/X)}",
"2018-01-10T12:02",
["26. Feb. 2018", "26. Feb. 2018"],
],
[
"Time[]{2016-07-13 X:X (X/X)}",
"2016-06-20T10:03",
["13. Juli 16", "13. Juli 16"],
],
[
"Time[]{2016-07-18 X:X (X/X)}",
"2016-06-28T09:21",
["18. Juli 18:25", "18. Juli 18:25"],
],
[
"Time[]{2017-06-09 X:X (X/X)}",
"2017-05-23T05:56",
["09. Juni 2017", "09. Juni 2017"],
],
[
"Time[]{2017-03-10 X:X (X/X)}",
"2017-01-30T12:26",
["10. M\u00e4rz 2017", "10. M\u00e4rz 2017"],
],
[
"Time[]{2018-03-10 X:X (X/X)}",
"2017-12-18T07:30",
["10. M\u00e4rz 2018", "10. M\u00e4rz 2018"],
],
[
"Time[]{2017-03-11 X:X (X/X)}",
"2017-01-30T12:26",
["11. M\u00e4rz 2017", "11. M\u00e4rz 2017"],
],
[
"Time[]{2018-06-12 X:X (X/X)}",
"2018-03-22T10:04",
["12. Juni 2018", "12. Juni 2018"],
],
[
"Time[]{2017-06-14 X:X (X/X)}",
"2017-06-02T07:23",
["14. Juni 2017", "14. Juni 2017"],
],
[
"Time[]{2018-03-10 14:30 (X/X)}",
"2018-03-05T11:52",
["10. March Saturday 14:30"],
],
[
"Time[]{2018-04-09 X:X (X/X)}",
"2018-03-13T11:59",
["09. April 2018", "09. April 2018"],
],
[
"Time[]{2016-12-09 X:X (X/X)}",
"2016-11-14T12:23",
["09. Dezember 2016", "09. Dezember 2016"],
],
[
"Time[]{2016-11-12 X:X (X/X)}",
"2016-04-07T07:45",
["12. November 2016", "12. November 2016"],
],
[
"Time[]{2017-10-12 X:X (X/X)}",
"2017-10-05T16:59",
[
"12. Oktober 2017",
"Donnerstag 12.10.2017",
"Thursday (12.)",
"12. Oktober 2017",
],
],
[
"Time[]{2017-09-12 X:X (X/X)}",
"2017-08-11T07:25",
[
"12. September 2017",
"Tuesday 12.9.",
"12. September 2017",
"Tuesday 12.9.",
],
],
[
"Time[]{2018-04-13 X:X (X/X)}",
"2018-03-16T12:34",
["13. April 2018", "13. April 2018"],
],
[
"Time[]{2018-02-13 X:X (X/X)}",
"2017-12-19T09:24",
["13. Februar 2018", "13. Februar 2018"],
],
[
"Time[]{2018-04-14 X:X (X/X)}",
"2018-04-08T17:07",
["14. April 2018", "14. April 2018"],
],
[
"Time[]{2018-03-13 X:X (X/X)}",
"2018-03-12T16:48",
["13. 03.", "13. 03.", "13. 03."],
],
[
"Interval[]{2017-07-11 X:X (X/X) - 2017-07-12 X:X (X/X)}",
"2017-06-28T15:41",
["11. auf 12."],
],
[
"Time[]{2018-03-03 X:X (X/evening)}",
"2018-02-02T15:44",
["23.-02.-03.03. abends"],
],
[
"Time[]{2017-01-16 X:X (X/X)}",
"2017-01-13T07:58",
["16.Januar 2017", "am Montag 16.01.17", "16.Januar 2017"],
],
[
"Time[]{2016-05-19 X:X (X/X)}",
"2016-04-12T12:42",
["19.5 08:05", "19.5 08:05", "19.5 08:05"],
],
["Time[]{2017-01-16 20:10 (X/X)}", "2016-11-18T06:43", ["16.1 8:10"]],
[
"Time[]{2018-03-15 16:01 (X/X)}",
"2018-02-28T10:19",
["12.03 - 15.03. 16:01", "12.03 - 15.03. 16:01"],
],
[
"Time[]{2017-10-21 X:X (X/X)}",
"2017-10-10T12:06",
["21.10 Samstag", "21.10 Samstag", "21.10 Samstag"],
],
["Time[]{2016-11-21 20:10 (X/X)}", "2016-09-19T08:44", ["21.11 8:10"]],
["Time[]{2016-11-14 20:10 (X/X)}", "2016-08-31T13:16", ["14.11 um 8:10"]],
[
"Interval[]{2017-11-24 11:00 (X/X) - 2017-11-24 13:00 (X/X)}",
"2017-11-17T09:47",
["24.11 ca. 11-13 Uhr"],
],
[
"Interval[]{2017-05-04 X:X (X/X) - 2017-05-05 X:X (X/X)}",
"2017-04-28T15:09",
["04.05 bis 05.05"],
],
[
"Interval[]{2017-10-04 X:X (X/X) - 2017-10-06 X:X (X/X)}",
"2017-09-29T14:29",
["04.10 bis 06.10"],
],
[
"Interval[]{2016-11-09 X:X (X/X) - 2016-11-10 X:X (X/X)}",
"2016-11-08T20:42",
["09.11 bis 10.11", "vom 09.11 bis 10.11"],
],
[
"Interval[]{2017-10-12 X:X (X/X) - 2017-10-13 X:X (X/X)}",
"2017-08-18T06:05",
["12.10 bis 13.10"],
],
[
"Interval[]{2018-03-13 X:X (X/X) - 2018-03-16 X:X (X/X)}",
"2018-03-05T12:12",
["13.03 bis 16.03"],
],
[
"Time[]{2017-06-13 X:X (X/X)}",
"2017-05-19T13:40",
["13.06 morning", "the 13.", "13.06 morning", "13.06 morning"],
],
[
"Time[]{2016-03-03 17:00 (X/X)}",
"2016-02-05T08:25",
["03.03 nachmittags ca. 5 Uhr"],
],
[
"Time[]{2017-01-31 X:X (X/X)}",
"2017-01-23T18:56",
["31.01. Tuesday", "31.01. Tuesday", "31.01. Tuesday"],
],
["Time[]{2017-09-20 22:10 (X/X)}", "2017-09-13T08:14", ["20.09. 22:10"]],
[
"Time[]{2017-09-15 X:X (X/X)}",
"2017-09-07T10:19",
["15.09. 14:21 Uhr", "15.09. 14:21 Uhr", "15.09. 14:21 Uhr"],
],
[
"Interval[]{2017-07-05 20:00 (X/X) - None}",
"2017-06-13T12:03",
["05.07. 2017 ab 08:00 Uhr"],
],
[
"Interval[]{2018-01-20 07:38 (X/X) - 2018-01-20 10:52 (X/X)}",
"2018-01-15T14:40",
["20.01. um 7:38 - 10:52am"],
],
[
"Interval[]{2017-06-12 13:15 (X/X) - 2017-06-12 14:15 (X/X)}",
"2017-06-08T08:12",
["12.06. um 13:15-14:15"],
],
[
"Interval[]{2016-11-03 20:15 (X/X) - None}",
"2016-11-02T09:46",
["03.11. ab 08:15 Uhr", "03.11. ab 08:15 Uhr"],
],
[
"Interval[]{2017-06-13 21:55 (X/X) - 2017-06-13 22:45 (X/X)}",
"2017-06-08T08:12",
["13.06. um 21:55-22:45"],
],
[
"Interval[]{2018-01-02 X:X (X/X) - 2018-01-05 X:X (X/X)}",
"2017-12-14T08:14",
["02.01.-05.01.2018 3 \u00dcN", "02.01.-05.01.2018 3 \u00dcN"],
],
[
"Interval[]{2017-09-14 18:00 (X/X) - 2017-09-14 20:00 (X/X)}",
"2017-08-11T11:31",
["12.09.17 - 14.09.17 18:00 - 20:00"],
],
[
"Interval[]{2017-02-10 23:49 (X/X) - None}",
"2017-02-09T16:00",
["10.02.17 ab 11:49", "10.02.17 ab 11:49"],
],
[
"Interval[]{2017-02-15 20:35 (X/X) - None}",
"2017-02-14T13:20",
["15.02.17 ab 08:35"],
],
[
"Interval[]{2017-12-07 12:50 (X/X) - 2017-12-07 14:10 (X/X)}",
"2017-11-20T13:30",
[
"07.12.17 um 12:50 - 14:10 Uhr",
"07.12.17 um 12:50 - 14:10 Uhr",
"07.12.17 um 12:50 - 14:10 Uhr",
],
],
[
"Time[]{2017-06-01 X:X (X/X)}",
"2017-03-13T08:29",
[
"01.06.2017 19:35",
"am 01. Juni 2017",
"01.06.2017 19:35",
"01.06.2017 19:35",
"am 01. Juni 2017",
],
],
[
"Time[]{2017-10-02 X:X (X/X)}",
"2017-08-25T05:49",
["02.10.2017 10:30", "02.10.2017 10:30", "02.10.2017 10:30"],
],
[
"Time[]{2018-03-06 X:X (X/X)}",
"2018-02-26T13:53",
[
"06.03.2018 06:30 Uhr",
"06.03.2018 18:55 Uhr",
"6th March 2018",
"06.03.2018 06:30 Uhr",
"06.03.2018 18:55 Uhr",
"6th March 2018",
"06.03.2018 06:30 Uhr",
"06.03.2018 18:55 Uhr",
"6th March 2018",
],
],
[
"Interval[]{2017-03-13 16:48 (X/X) - 2017-03-13 20:08 (X/X)}",
"2017-03-07T09:47",
[
"13.03.2017 um 16:48 - 20:08",
"13.03.2017 um 16:48 - 20:08",
"13.03.2017 um 16:48 - 20:08",
],
],
[
"Interval[]{2017-04-07 21:00 (X/X) - 2017-04-07 22:00 (X/X)}",
"2017-03-20T18:46",
[
"07.04.2017 ca. 9-10 Uhr",
"07.04.2017 ca. 9-10 Uhr",
"07.04.2017 ca. 9-10 Uhr",
],
],
[
"Interval[]{2017-04-03 22:00 (X/X) - 2017-04-03 23:00 (X/X)}",
"2017-03-20T18:46",
[
"03.04.2017 ca. 10 - 11 Uhr",
"03.04.2017 ca. 10 - 11 Uhr",
"03.04.2017 ca. 10 - 11 Uhr",
],
],
[
"Interval[]{2018-03-05 22:00 (X/X) - 2018-03-05 23:00 (X/X)}",
"2018-02-20T09:37",
[
"05.03.2018 ca. 10-11 Uhr",
"05.03.2018 ca. 10-11 Uhr",
"05.03.2018 ca. 10-11 Uhr",
],
],
# int-int
[
"Interval[]{2018-02-20 10:00 (X/X) - 2018-02-20 15:00 (X/X)}",
"2018-02-20T09:37",
[
"today 10-15",
"today 10-15",
"today 10-15",
"today 10-15",
"today 10-15",
"today 10-15",
"today 10-15",
"today 10-15",
"today 10-15",
],
],
[
"Interval[]{2018-02-20 10:00 (X/X) - 2018-02-20 11:00 (X/X)}",
"2018-02-20T09:37",
[
"today 10-11am",
"today 10-11am",
"today 10-11am",
],
],
[
"Time[]{2017-06-23 22:00 (X/X)}",
"2017-06-02T09:41",
["23.06.2017 ca. 10Uhr", "23.06.2017 ca. 10Uhr"],
],
# [
# "Interval[]{2018-02-20 21:00 (X/X) - 2018-02-21 03:00 (X/X)}",
# "2018-02-20T09:37",
# [
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# "9pm-3am",
# ],
# ],
[
"Interval[]{2018-02-20 X:X (X/X) - 2018-02-21 X:X (X/X)}",
"2018-02-16T08:59",
["20.02.2018 bis 21.02.20178"],
],
[
"Interval[]{2017-05-10 18:00 (X/X) - 2017-05-10 20:00 (X/X)}",
"2017-05-04T19:05",
[
"10.05.2017 gegen 18-20 Uhr",
"10.05.2017 gegen 18-20 Uhr",
"10.05.2017 gegen 18-20 Uhr",
],
],
[
"Interval[]{2017-11-13 22:00 (X/X) - 2017-11-13 23:00 (X/X)}",
"2017-10-25T09:25",
["13.11.2017 gegen 10-11 Uhr", "13.11.2017 gegen 10-11 Uhr"],
],
[
"Interval[]{2017-04-24 21:30 (X/X) - 2017-04-24 22:00 (X/X)}",
"2017-04-13T12:41",
[
"24.04.2017 gegen 09:30 - 10:00 Uhr",
"24.04.2017 gegen 09:30 - 10:00 Uhr",
"24.04.2017 gegen 09:30 - 10:00 Uhr",
],
],
[
"Time[]{2018-03-02 14:00 (X/X)}",
"2018-02-23T15:38",
[
"02.03.2018 gegen 14:00 Uhr nachmittags",
"02.03.2018 gegen 14:00 Uhr nachmittags",
],
],
[
"Time[]{2017-07-18 X:X (X/evening)}",
"2017-07-11T09:03",
["18/07 sp\u00e4t abends", "18/07 sp\u00e4t abends", "18/07 sp\u00e4t abends"],
],
[
"Time[]{2016-12-12 13:40 (X/X)}",
"2016-12-09T18:07",
[
"01:40 Mon 12 Dec 2016",
"01:40 Mon 12 Dec 2016",
"01:40 Mon 12 Dec 2016",
],
],
[
"Time[]{2017-11-20 20:25 (X/X)}",
"2017-11-14T08:41",
[
"08:25 Monday 20 November 2017",
"08:25 Monday 20 November 2017",
"08:25 Monday 20 November 2017",
],
],
["Time[]{2017-08-02 15:42 (X/X)}", "2017-07-31T09:05", ["15:42 diesen Mittwoch"]],
[
"Time[]{2017-03-15 19:20 (X/X)}",
"2017-03-15T10:46",
["15 Mar 19:20", "15 Mar 19:20", "15 Mar 19:20"],
],
["Time[]{2017-08-10 X:X (X/X)}", "2017-08-09T14:45", ["10 Aug", "10 Aug"]],
["Time[]{2016-11-28 X:X (X/X)}", "2016-11-18T12:56", ["28 Nov 2016", "28 Nov 2016"]],
["Time[]{2017-09-18 X:X (X/X)}", "2017-09-07T08:03", ["2017-09-18", "2017-09-18"]],
["Time[]{2017-09-20 X:X (X/X)}", "2017-09-07T08:03", ["2017-09-20", "2017-09-20"]],
[
"Time[]{2016-10-30 X:X (X/X)}",
"2016-10-05T13:20",
["2016-10-30 12:05", "2016-10-30 12:05", "2016-10-30 12:05"],
],
["Time[]{2016-12-16 19:55 (X/X)}", "2016-11-23T16:05", ["2016-12-16 19:55"]],
["Time[]{2016-12-16 22:55 (X/X)}", "2016-11-23T16:05", ["2016-12-16 22:55"]],
["Time[]{2016-12-17 13:25 (X/X)}", "2016-11-23T18:55", ["2016-12-17 01:25"]],
["Time[]{2016-12-17 14:55 (X/X)}", "2016-11-23T16:05", ["2016-12-17 02:55"]],
["Time[]{2016-12-17 17:50 (X/X)}", "2016-11-23T18:55", ["2016-12-17 05:50"]],
["Time[]{2016-12-17 19:00 (X/X)}", "2016-11-23T18:55", ["2016-12-17 07:00"]],
["Time[]{2016-12-17 19:20 (X/X)}", "2016-11-23T16:05", ["2016-12-17 07:20"]],
["Time[]{2016-12-17 20:15 (X/X)}", "2016-11-23T18:55", ["2016-12-17 08:15"]],
["Time[]{2016-12-17 12:00 (X/X)}", "2016-11-23T16:05", ["2016-12-17 12:00"]],
["Time[]{2016-12-17 13:05 (X/X)}", "2016-11-23T16:05", ["2016-12-17 13:05"]],
[
"Time[]{2016-05-16 X:X (X/X)}",
"2016-03-04T16:16",
["16th May 2016", "16th May 2016", "16th May 2016"],
],
[
"Time[]{2017-09-05 X:X (X/X)}",
"2017-06-27T10:47",
["05th September 2017", "05th September 2017"],
],
[
"Time[]{2018-04-07 X:X (X/X)}",
"2018-03-05T14:43",
["07th April 2018", "07th April 2018", "07th April 2018"],
],
[
"Time[]{2018-02-10 X:X (X/X)}",
"2018-01-29T03:05",
["10th February 2018", "10th February 2018"],
],
[
"Time[]{2018-03-11 X:X (X/X)}",
"2017-11-10T12:37",
["11th March 2018", "11th March 2018"],
],
[
"Time[]{2016-11-24 12:50 (X/X)}",
"2016-11-16T16:38",
["24th 12:50", "24th 12:50"],
],
[
"Time[]{2016-12-24 X:X (X/X)}",
"2016-12-11T21:39",
["24th 25th December", "24th 25th December", "24th 25th December"],
],
[
"Time[]{2017-05-10 X:X (X/X)}",
"2017-05-08T15:39",
["10th of May 2017", "10th of May 2017", "10th of May 2017"],
],
[
"Time[]{2018-01-12 X:X (X/X)}",
"2017-10-25T07:59",
["am Fr. 12. Januar 2018", "am Fr. 12. Januar 2018"],
],
[
"Time[]{2018-03-30 X:X (X/evening)}",
"2018-03-11T21:48",
["am Donnerstag Abend 30.3"],
],
[
"Time[]{2018-05-25 18:45 (X/X)}",
"2018-04-11T10:04",
[
"on Friday 25 may at 18:45 in the evening",
"on Friday 25 may at 18:45 in the evening",
],
],
[
"Time[]{2018-02-23 X:X (X/X)}",
"2018-01-05T16:44",
["on Friday 23rd", "ab Freitag 23.02.2018", "on Friday 23/2/2018"],
],
["Time[]{2018-01-18 X:X (X/X)}", "2018-01-16T15:09", ["am Donnerstag den 18."]],
[
"Time[]{2017-11-08 X:X (X/X)}",
"2017-09-05T08:17",
["am Mittwoch, den 08. November 2017", "am Mittwoch, den 08. November 2017"],
],
["Time[]{2017-05-03 X:X (X/X)}", "2017-04-24T12:02", ["am 3."]],
["Time[]{2017-07-15 X:X (X/X)}", "2017-06-21T11:02", ["am 15"]],
["Time[]{2017-08-07 X:X (X/X)}", "2017-08-04T14:25", ["am 07."]],
["Time[]{2016-11-13 X:X (X/X)}", "2016-10-18T07:23", ["am 13."]],
[
"Time[]{2016-06-13 X:X (X/X)}",
"2016-03-21T11:20",
["am 13. Juni 2016", "am 13. Juni 2016"],
],
[
"Time[]{2018-03-12 X:X (X/morning)}",
"2018-03-02T11:56",
["am 12. M\u00e4rz 2018 morgens"],
],
# [
# "Time[]{2018-06-13 X:X (X/morning)}",
# "2018-03-26T10:02",
# ["am 13. Juni 2018 morgens"],
# ],
[
"Time[]{2016-11-16 21:50 (X/X)}",
"2016-11-03T10:07",
["am 16. November 2016 09:50 Uhr"],
],
[
"Time[]{2022-12-24 X:X (X/X)}",
"2022-11-30T10:07",
["12/24", "12/24", "24.12", "12.24", "12/24", "12/24", "12/24", "12/24", "12/24", "12/24", "12/24", "12/24",
"12"
"/24", "12/24"],
],
[
"Time[]{2023-08-15 X:X (X/X)}",
"2022-11-30T10:07",
["meet with adam 8/15", "meet with adam 8/15", "meet with adam 8/15", "meet with adam 8/15",
"meet with martin 8/15", "meet with adam 8/15", "meet with adam 8/15", "meet with martin 8/15",
"meet with adam 8/15", "meet with adam 8/15", "meet with "
"martin 8/15",
'meet with adam 8/15'],
],
[
"Time[]{2022-12-20 X:X (X/X)}",
"2022-11-30T10:07",
["meet with adam 12/20", "meet with adam 12/20", "meet with adam 12/20", "meet with adam 12/20",
"meet with adam 12/20", "meet with adam 12/20", "meet with adam 12/20", "meet with adam 12/20",
"meet with adam 12/20", "meet with martin 12/20",
"meet with martin 12/20", "meet with martin 12/20"],
],
[
"Time[]{2023-03-13 X:X (X/X)}",
"2022-11-30T10:07",
["3/13", "3/13", "3/13", "3/13", "3/13", "3/13", "3/13", "3/13", "3/13", "3/13"],
],
[
"Time[]{2023-06-14 X:X (X/X)}",
"2022-11-30T10:07",
["6/14", "6/14", "6/14", "6/14", "6/14", "6/14", "6/14", "6/14"],
],
[
"Time[]{2023-10-19 X:X (X/X)}",
"2022-11-30T10:07",
["10/19", "10/19", "10/19", "10/19", "10/19", "10/19", "10/19", "10/19"],
],
[
"Time[]{2022-12-30 X:X (X/X)}",
"2022-11-30T10:07",
["12/30", "12/30", "12/30", "12/30", "12/30", "12/30", "12/30", "12/30", "12/30", "12/30", "12/30", "12/30"],
],
[
"Time[]{2022-12-24 X:X (X/X)}",
"2022-11-30T10:07",
["12/24", "24.12", "12.24", "12/24", "12/24", "12/24", "12/24", "12/24", "12/24", "12/24", "12/24", "12"
"/24",
"12/24"],
],
[
"Time[]{2017-10-04 X:X (X/evening)}",
"2017-09-25T14:37",
["am 04. Oktober 2017 abends"],
],
[
"Interval[]{None - 2017-11-20 22:30 (X/X)}",
"2017-11-07T14:16",
["am 20. November 2017 sp\u00e4testens 10:30 Uhr"],
],
# ["Time[]{2018-04-11 X:X (X/morning)}", "2018-03-27T12:23", ["am 11. morgens"]],
# ["Time[]{2018-02-14 X:X (X/morning)}", "2018-01-17T11:48", ["am 14. morgens"]],
# [
# "Time[]{2017-11-14 X:X (X/X)}",
# "2017-09-07T12:57",
# ["am 14.November 2017", "am 14.November 2017"],
# ],
# [
# "Time[]{2017-01-20 X:X (X/morning)}",
# "2016-11-15T10:25",
# ["am 20.Januar 2017 morgens"],
# ],
# [
# "Time[]{2016-08-15 X:X (X/afternoon)}",
# "2016-06-23T11:34",
# ["am 15.8. am Nachmittag"],
# ],
# ["Time[]{2018-04-15 X:X (X/evening)}", "2018-03-14T15:40", ["am 15.04 am Abend"]],
# [
# "Time[]{2018-04-11 X:X (X/lateafternoon)}",
# "2018-03-16T11:54",
# ["am 11.04 sp\u00e4tnachmittags"],
# ],
# [
# "Time[]{2017-12-15 X:X (X/lateevening)}",
# "2017-12-08T10:34",
# ["am 15.12 sp\u00e4t abends"],
# ],
# [
# "Time[]{2018-03-16 X:X (X/afternoon)}",
# "2018-03-08T04:32",
# ["am 16.03. am Nachmittag"],
# ],
# [
# "Time[]{2017-12-17 X:X (X/afternoon)}",
# "2017-12-12T06:45",
# ["am 17.12. am Nachmittag"],
# ],
# ["Time[]{2018-01-25 X:X (X/evening)}", "2018-01-16T17:07", ["am 25.01. am Abend"]],
# [
# "Time[]{2018-01-02 X:X (X/afternoon)}",
# "2017-12-18T08:47",
# ["am 02.01. am nachmittag"],
# ],
[
"Interval[]{2017-08-28 20:15 (X/X) - 2017-08-28 21:20 (X/X)}",
"2017-08-22T12:26",
["am 28.08.17 08:15 - 09:20", "am 28.08.17 08:15 - 09:20"],
],
[
"Interval[]{2018-03-02 14:30 (X/X) - 2018-03-02 16:00 (X/X)}",
"2018-02-16T17:50",
["am 02.03.18 14:30 - 16:00 Uhr", "am 02.03.18 14:30 - 16:00 Uhr"],
],
[
"Interval[]{2018-05-04 17:35 (X/X) - 2018-05-04 18:30 (X/X)}",
"2018-03-26T08:13",
["am 04.05.18 17:35 - 18:30 Uhr", "am 04.05.18 17:35 - 18:30 Uhr"],
],
[
"Interval[]{2017-12-21 15:30 (X/X) - 2017-12-21 16:40 (X/X)}",
"2017-11-22T12:23",
["am 21.12.17 15:30 - 16:40", "am 21.12.17 15:30 - 16:40"],
],
[
"Interval[]{2018-03-14 17:45 (X/X) - 2018-03-14 19:10 (X/X)}",
"2018-03-01T12:42",
["am 14.03.18 17:45 -- 19:10 Uhr", "am 14.03.18 17:45 -- 19:10 Uhr"],
],
[
"Interval[]{2017-11-02 15:00 (X/X) - 2017-11-02 18:00 (X/X)}",
"2017-10-17T08:57",
["am 02.11.2017 15-18 Uhr", "am 02.11.2017 15-18 Uhr"],
],
[
"Interval[]{2018-04-04 19:10 (X/X) - 2018-04-04 20:20 (X/X)}",
"2018-03-29T11:39",
["am 04.04.2018 07:10 - 08:20", "am 04.04.2018 07:10 - 08:20"],
],
[
"Interval[]{2018-02-06 19:10 (X/X) - 2018-02-06 20:40 (X/X)}",
"2017-12-22T09:56",
["am 06.02.2018 07:10 - 08:40", "am 06.02.2018 07:10 - 08:40"],
],
[
"Interval[]{2018-02-06 19:50 (X/X) - 2018-02-06 21:15 (X/X)}",
"2017-12-22T09:56",
["am 06.02.2018 19:50 - 21:15", "am 06.02.2018 19:50 - 21:15"],
],
[
"Interval[]{2018-03-07 16:03 (X/X) - 2018-03-07 20:07 (X/X)}",
"2018-02-19T09:03",
["am 07.03.2018 16:03 - 20:07", "am 07.03.2018 16:03 - 20:07"],
],
[
"Interval[]{2017-06-12 18:50 (X/X) - 2017-06-12 20:00 (X/X)}",
"2017-06-08T11:07",
["am 12.06.2017 06:50 - 08:00", "am 12.06.2017 06:50 - 08:00"],
],
[
"Interval[]{2017-11-16 18:05 (X/X) - 2017-11-16 19:35 (X/X)}",
"2017-11-09T11:59",
["am 16.11.2017 18:05 - 19:35 Uhr", "am 16.11.2017 18:05 - 19:35 Uhr"],
],
[
"Interval[]{2017-07-17 19:00 (X/X) - 2017-07-17 21:00 (X/X)}",
"2017-07-11T11:53",
["am 17.07.2017 07:00-09:00 Uhr", "am 17.07.2017 07:00-09:00 Uhr"],
],
[
"Time[]{2018-06-07 19:00 (X/X)}",
"2018-03-05T13:15",
["am 07.06.2018 um 07.00 Uhr morgens"],
],
[
"Interval[]{X-X-X 20:00 (X/X) - None}",
"2017-06-14T15:35",
["ab 08:00 Uhr", "ab 08:00 Uhr", "ab 08:00 Uhr"],
],
[
"Interval[]{2017-07-20 18:00 (X/X) - None}",
"2017-06-23T08:54",
["ab 18:00 Uhr 20.07.2017"],
],
[
"Interval[]{2016-11-28 08:00 (X/X) - None}",
"2016-11-14T13:36",
["ab 08:00 Uhr am 28.11.2016"],
],
[
"Interval[]{X-X-X 16:00 (X/X) - None}",
"2016-12-16T08:09",
["ab 16Uhr", "ab 16Uhr", "ab 16Uhr"],
],
[
"Interval[]{2017-02-10 14:00 (X/X) - None}",
"2017-01-29T14:13",
["ab 14h am 10.02.2017"],
],
[
"Time[]{2018-03-22 X:X (X/X)}",
"2018-03-15T11:38",
["on the 22.", "Donnerstag 22.3."],
],
[
"Time[]{2017-01-24 X:X (X/evening)}",
"2017-01-24T13:24",
["ab heute Abend", "ab heute Abend", "ab heute Abend"],
],
[
"Interval[]{2022-12-05 X:X (X/X) - 2022-12-06 X:X (X/X)}",
"2022-11-29T15:35",
[
"Monday to tuesday",
"Monday to tuesday",
],
],
[
"Interval[]{2017-11-08 X:X (X/X) - 2017-11-10 X:X (X/X)}",
"2017-10-12T07:20",
["vom 8.11 bis 10.11"],
],
["Time[]{2017-06-12 X:X (X/X)}", "2017-06-08T08:38", ["the 12."]],
["Time[]{2017-03-09 X:X (X/X)}", "2017-03-07T07:36", ["vom 09."]],
[
"Time[]{2018-04-20 X:X (X/noon)}",
"2018-04-05T08:59",
["vom 16. - 20. April Mittags", "vom 16. - 20. April Mittags"],
],
[
"Interval[]{2017-09-04 X:X (X/X) - 2017-09-06 X:X (X/X)}",
"2017-08-24T12:11",
["vom 04.09 bis 06.09"],
],
[
"Interval[]{2018-02-07 X:X (X/X) - 2018-02-08 X:X (X/X)}",
"2018-01-11T16:34",
["vom 07.02 bis 08.02"],
],
[
"Interval[]{2017-05-12 X:X (X/X) - 2017-05-13 X:X (X/X)}",
"2017-04-13T10:10",
["vom 12.05 bis 13.05"],
],
[
"Interval[]{2017-08-14 X:X (X/X) - 2017-08-16 X:X (X/X)}",
"2017-07-21T08:09",
["vom 14.08 bis 16.08"],
],
[
"Interval[]{2017-03-15 X:X (X/X) - 2017-03-16 X:X (X/X)}",
"2017-03-14T08:54",
["vom 15.03 bis 16.03"],
],
[
"Interval[]{2017-01-16 X:X (X/X) - 2017-01-19 X:X (X/X)}",
"2017-01-10T08:23",
["vom 16.01 bis 19.01"],
],
[
"Interval[]{2018-02-18 X:X (X/X) - 2018-02-23 X:X (X/X)}",
"2018-02-12T13:36",
["vom 18.02 bis 23.02"],
],
[
"Time[]{2018-01-04 21:00 (X/X)}",
"2017-12-18T15:50",
["vom 02.01. - 04.01. um 21:00 Uhr", "vom 02.01. - 04.01. um 21:00 Uhr"],
],
[
"Interval[]{2017-06-07 X:X (X/X) - 2017-06-08 X:X (X/X)}",
"2017-06-06T10:56",
["f\u00fcr 07.06. bis 08.06"],
],
[
"Interval[]{2017-11-02 X:X (X/X) - 2017-11-03 X:X (X/X)}",
"2017-10-16T13:21",
["vom 02.11. bis 03.11"],
],
[
"Interval[]{2017-02-07 X:X (X/X) - 2017-02-10 X:X (X/X)}",
"2017-02-03T09:16",
["vom 07.02. bis 10.02"],
],
[
"Interval[]{2017-01-09 X:X (X/X) - 2017-01-10 X:X (X/X)}",
"2017-01-04T08:44",
["vom 09.01. bis 10.01"],
],
[
"Interval[]{2017-07-10 X:X (X/X) - 2017-07-12 X:X (X/X)}",
"2017-06-20T11:06",
["vom 10.07. bis 12.07"],
],
[
"Time[]{2017-07-06 16:00 (X/X)}",
"2017-07-06T06:10",
["06.07 16:00", "06.07 16:00", "06.07 16:00"],
],
[
"Interval[]{None - 2016-10-04 08:30 (X/X)}",
"2016-09-07T14:13",
["vor 08:30 Uhr am 04.10."],
],
[
"Time[]{2017-07-05 X:X (X/morning)}",
"2017-07-04T15:51",
["morgen Mittwoch", "morgen Mittwoch"],
],
[
"Time[]{2017-08-02 18:30 (X/X)}",
"2017-07-25T15:21",
["kommenden Mittwoch den 02.August 2017 06:30"],
],
# ["Time[]{2017-10-26 X:X (X/first)}", "2017-10-25T12:42", ["earliest 26.10"]],
[
"Interval[]{2017-02-06 X:X (X/X) - 2017-02-07 X:X (X/X)}",
"2017-02-06T13:13",
[
"heute 06.02 bis morgen 7.02",
"heute 06.02 bis morgen 7.02",
"heute 06.02 bis morgen 7.02",
],
],
# [
# "Interval[]{None - 2017-12-15 X:X (X/afternoon)}",
# "2017-12-14T20:43",
# ["tomorrow 15.12 before afternoon"],
# ],
[
"Time[]{2016-11-21 X:X (X/X)}",
"2016-11-21T16:18",
["heute 21.11.", "heute 21.11.", "heute 21.11."],
],
[
"Interval[]{2016-10-05 18:00 (X/X) - None}",
"2016-09-07T14:13",
[
"nach 18:00 Uhr am 05.10.",
"nach 18:00 Uhr am 05.10.",
"nach 18:00 Uhr am 05.10.",
],
],
[
"Interval[]{2018-02-07 15:00 (X/X) - None}",
"2018-01-30T12:32",
["nach 15:00 Uhr am 07.02.2018"],
],
[
"Interval[]{X-X-X 16:00 (X/X) - None}",
"2016-09-17T08:01",
["after 4pm", "after 4pm", "after 4pm"],
],
[
"Interval[]{X-X-X 19:00 (X/X) - None}",
"2017-11-22T07:12",
["abends ab 19:00", "abends ab 19:00", "abends ab 19:00"],
],
["Time[]{2016-09-09 X:X (X/morning)}", "2016-09-08T11:04", ["morgen frueh"]],
[
"Interval[]{2017-11-02 14:00 (X/X) - 2017-11-02 16:00 (X/X)}",
"2017-11-02T07:03",
[
"heute zwischen 14 und 16 Uhr",
"heute zwischen 14 und 16 Uhr",
"heute zwischen 14 und 16 Uhr",
],
],
[
"Interval[]{2017-11-14 07:30 (X/X) - 2017-11-14 12:52 (X/X)}",
"2017-11-13T09:59",
["morgen, den 14.11.2017 07:30 - 12:52 Uhr"],
],
[
"Time[]{2017-11-06 X:X (X/X)}",
"2017-11-03T07:20",
[
"KW 45 bis KW 51 von montags bis freitags 06.11.2017",
"on Monday - 06.11.2017",
"KW 45 bis KW 51 von montags bis freitags 06.11.2017",
"November 6, 2017",
"Montag 06.11",
"on Monday - 06.11.2017",
],
],
["Time[]{2017-07-07 X:X (X/X)}", "2017-05-31T08:47", ["Am Freitag 07.07.2017"]],
[
"Time[]{2017-06-29 X:X (X/X)}",
"2017-06-19T12:47",
["Am Donnerstag den 29.06", "Am Donnerstag den 29.06"],
],
[
"Interval[]{2017-06-26 19:50 (X/X) - 2017-06-26 22:00 (X/X)}",
"2017-06-20T11:10",
["Mon 26th June 07:50-10:00"],
],
[
"Time[]{2016-11-17 13:51 (X/X)}",
"2016-11-14T08:48",
["Donnerstag Nachmittag 13:51"],
],
[
"Time[]{2017-12-21 19:00 (X/X)}",
"2017-12-18T10:37",
[
"Diesen Donnerstag, 21.12. gegen 07:00",
"Diesen Donnerstag, 21.12. gegen 07:00",
],
],
["Time[]{2017-11-02 17:50 (X/X)}", "2017-10-29T18:23", ["Thurs 2 Nov 1750"]],
["Time[]{2017-10-06 14:00 (X/X)}", "2017-09-29T13:47", ["Freitag 14 Uhr"]],
["Time[]{2017-10-12 22:45 (X/X)}", "2017-10-09T09:05", ["Donnerstag 10:45 Uhr"]],
[
"Time[]{2017-09-07 X:X (X/X)}",
"2017-05-23T12:46",
["Donnerstag 07.09.17", "am Donnerstag 7.9.2017", "am Donnerstag 07.09.17"],
],
["Time[]{2016-12-15 X:X (X/X)}", "2016-11-29T08:43", ["Donnerstag 15.12.16"]],
["Time[]{2017-08-24 X:X (X/X)}", "2017-08-16T07:10", ["Donnerstag 24.08.17"]],
["Time[]{2017-04-07 X:X (X/X)}", "2017-03-06T13:32", ["Freitag 07.04.17"]],
["Time[]{2017-11-03 X:X (X/X)}", "2017-11-01T07:20", ["Donnerstag 03.11.2017"]],
["Time[]{2017-04-06 X:X (X/X)}", "2017-03-09T14:13", ["Donnerstag 06.04.2017"]],
["Time[]{2018-06-07 X:X (X/X)}", "2017-11-16T09:29", ["Donnerstag 07.06.2018"]],
["Time[]{2018-02-08 X:X (X/X)}", "2017-11-16T09:29", ["Donnerstag 08.02.2018"]],
[
"Time[]{2018-03-08 X:X (X/X)}",
"2017-11-16T09:29",
["Donnerstag 08.03.2018", "am Donnerstag 08.03.2018"],
],
["Time[]{2018-01-11 X:X (X/X)}", "2017-11-16T09:29", ["Donnerstag 11.01.2018"]],
[
"Time[]{2018-04-12 X:X (X/X)}",
"2017-11-16T09:29",
["Donnerstag 12.04.2018", "Donnerstag 12.04."],
],
["Time[]{2017-07-03 18:48 (X/X)}", "2017-06-30T13:27", ["Montag 06:48h"]],
["Time[]{2016-04-14 14:50 (X/X)}", "2016-04-12T16:36", ["Donnerstag 14:50"]],
["Time[]{2017-05-12 23:30 (X/X)}", "2017-05-08T12:58", ["Freitag 11:30"]],
["Time[]{2016-04-20 16:30 (X/X)}", "2016-04-15T11:21", ["Mittwoch 16:30"]],
["Time[]{2018-01-31 17:00 (X/X)}", "2018-01-25T11:04", ["Mittwoch 17:00"]],
["Time[]{2018-02-06 17:00 (X/X)}", "2018-02-02T13:47", ["Dienstag 05:00 Uhr"]],
["Time[]{2017-05-30 18:24 (X/X)}", "2017-05-29T06:22", ["Dienstag 06:24 Uhr"]],
["Time[]{2018-02-20 16:00 (X/X)}", "2018-02-16T10:44", ["Dienstag 16:00 Uhr"]],
["Time[]{2017-05-30 16:25 (X/X)}", "2017-05-29T06:22", ["Dienstag 16:25 Uhr"]],
[
"Interval[]{2017-07-10 18:30 (X/X) - 2017-07-10 19:50 (X/X)}",
"2017-05-31T07:58",
["Monday 10th of July 18:30 - 19:50"],
],
[
"Time[]{2017-06-28 22:10 (X/X)}",
"2017-06-22T07:47",
["Wednesday 28th of June 10:10SXF"],
],
["Time[]{2016-04-07 17:00 (X/X)}", "2016-04-05T12:38", ["Donnerstag 5pm"]],
[
"Time[]{2017-03-09 20:35 (X/X)}",
"2017-02-24T10:51",
["Sunday 9th of March 20:35CDG"],
],
[
"Interval[]{2017-06-12 18:00 (X/X) - None}",
"2017-06-08T08:38",
["Monday evening 12.06.2017 after 18:00"],
],
["Time[]{2017-05-18 18:00 (X/X)}", "2017-05-15T11:59", ["Donnerstag abend 18:00"]],
["Time[]{2017-01-03 X:X (X/X)}", "2016-12-14T08:33", ["Dienstag, 3.1.2017"]],
["Time[]{2017-01-24 X:X (X/X)}", "2016-12-14T08:33", ["Dienstag, 24.1.2017"]],
["Time[]{2016-11-25 10:00 (X/X)}", "2016-11-22T15:30", ["Friday, 25.11. 10 am"]],
[
"Time[]{2017-09-14 X:X (X/X)}",
"2017-09-01T10:01",
["Donnerstag 14.09.17", "Donnerstag 14.09"],
],
["Time[]{2016-06-16 X:X (X/X)}", "2016-06-03T09:37", ["Donnerstag 16.06.16"]],
["Time[]{2018-02-01 X:X (X/X)}", "2018-01-19T15:29", ["Donnerstag 01.02.2018"]],
["Time[]{2017-05-05 12:55 (X/X)}", "2017-05-03T18:24", ["Freitag 12:55"]],
[
"Time[]{2017-11-17 16:10 (X/X)}",
"2017-11-09T10:54",
["Friday 17th Nov 4:10 pm"],
],
["Time[]{2018-02-02 00:45 (X/X)}", "2018-01-15T16:51", ["2 FEB 00:45"]],
["Time[]{2018-02-07 20:00 (X/X)}", "2018-01-08T21:10", ["7 FEB 08:00"]],
["Time[]{2018-04-06 16:30 (X/X)}", "2018-03-29T09:26", ["6 APRIL 16:30"]],
["Time[]{2017-12-01 19:10 (X/X)}", "2017-11-20T19:42", ["1 Dec 0710"]],
["Time[]{2017-12-01 20:15 (X/X)}", "2017-11-20T19:42", ["1 Dec 0815"]],
["Time[]{2018-02-02 17:25 (X/X)}", "2018-01-24T10:06", ["2 Feb 0525"]],
["Time[]{2018-01-02 14:30 (X/X)}", "2017-12-09T12:31", ["2 Jan 1430"]],
["Time[]{2018-01-02 23:25 (X/X)}", "2017-12-09T12:31", ["2 Jan 2325"]],
["Time[]{2017-11-02 12:35 (X/X)}", "2017-08-25T12:23", ["2 Nov 1235"]],
["Time[]{2017-11-02 18:15 (X/X)}", "2017-08-25T12:23", ["2 Nov 1815"]],
["Time[]{2017-11-02 19:40 (X/X)}", "2017-10-25T09:35", ["2 Nov 1940"]],
["Time[]{2017-12-03 20:25 (X/X)}", "2017-11-20T19:42", ["3 Dec 2025"]],
["Time[]{2017-12-03 21:25 (X/X)}", "2017-11-20T19:42", ["3 Dec 2125"]],
["Time[]{2018-03-09 19:55 (X/X)}", "2018-02-20T11:11", ["9 March 0755"]],
["Time[]{2016-10-04 22:35 (X/X)}", "2016-09-12T08:20", ["4. Okt 22:35"]],
["Time[]{2017-06-01 14:15 (X/X)}", "2017-05-12T15:32", ["1. Juni 14:15"]],
["Time[]{2017-07-05 21:34 (X/X)}", "2017-06-29T14:30", ["5. Juli 09:34"]],
["Time[]{2017-07-05 13:47 (X/X)}", "2017-06-29T14:30", ["5. Juli 13:47"]],
["Time[]{2017-06-02 22:20 (X/X)}", "2017-05-12T15:32", ["2. Juni 10:20 Uhr"]],
["Time[]{2017-09-06 22:30 (X/X)}", "2017-08-07T14:26", ["6. Sept 10:30"]],
["Time[]{2018-02-08 18:35 (X/X)}", "2018-01-17T10:14", ["8. Februar 6:35"]],
["Time[]{2017-08-02 16:45 (X/X)}", "2017-07-10T10:57", ["2. August 16:45"]],
["Time[]{2016-04-07 12:30 (X/X)}", "2016-03-30T12:28", ["7. April 12:30h"]],
["Time[]{2017-12-04 21:30 (X/X)}", "2017-11-24T12:39", ["4. Dezember 21:30"]],
["Time[]{2017-08-01 14:08 (X/X)}", "2017-07-31T11:31", ["1. August 14:08 Uhr"]],
["Time[]{2017-10-06 X:X (X/X)}", "2017-09-28T10:01", ["6. 10."]],
["Time[]{2017-02-07 18:05 (X/X)}", "2016-12-16T09:02", ["7.2.2017 um 18:05"]],
["Time[]{2017-03-24 19:05 (X/X)}", "2017-03-13T15:25", ["7:05 Friday 24. march"]],
["Time[]{2017-07-02 15:10 (X/X)}", "2017-05-31T12:41", ["02 JUL 15:10"]],
["Time[]{2017-07-02 16:30 (X/X)}", "2017-05-31T12:41", ["02 JUL 16:30"]],
["Time[]{2018-01-04 12:20 (X/X)}", "2017-12-06T12:36", ["04 JAN 12:20"]],
["Time[]{2017-06-04 19:45 (X/X)}", "2017-05-17T09:16", ["04 JUN 07:45"]],
["Time[]{2017-06-04 21:35 (X/X)}", "2017-05-17T09:16", ["04 JUN 09:35"]],
["Time[]{2018-01-05 00:10 (X/X)}", "2017-12-06T12:36", ["05 JAN 00:10"]],
["Time[]{2017-07-06 20:00 (X/X)}", "2017-05-30T13:31", ["06 JUL 20:00"]],
["Time[]{2017-07-06 21:45 (X/X)}", "2017-05-30T13:31", ["06 JUL 21:45"]],
["Time[]{2017-06-06 20:45 (X/X)}", "2017-05-17T09:16", ["06 JUN 20:45"]],
["Time[]{2017-06-06 22:35 (X/X)}", "2017-05-17T09:16", ["06 JUN 22:35"]],
["Time[]{2017-07-07 19:05 (X/X)}", "2017-06-21T10:04", ["07 JUL 07:05"]],
["Time[]{2017-07-07 17:25 (X/X)}", "2017-06-21T10:04", ["07 JUL 17:25"]],
["Time[]{2017-07-07 19:10 (X/X)}", "2017-05-30T13:31", ["07 JUL 19:10"]],
["Time[]{2017-06-07 19:55 (X/X)}", "2017-05-17T09:16", ["07 JUN 07:55"]],
["Time[]{2017-06-07 20:50 (X/X)}", "2017-05-17T09:16", ["07 JUN 08:50"]],
["Time[]{2017-06-08 21:50 (X/X)}", "2017-05-17T09:16", ["08 JUN 09:50"]],
["Time[]{2018-01-10 19:10 (X/X)}", "2017-12-30T15:14", ["10 JAN 19:10"]],
["Time[]{2018-01-10 22:05 (X/X)}", "2017-12-30T15:14", ["10 JAN 22:05"]],
["Time[]{2017-10-10 20:40 (X/X)}", "2017-09-09T06:12", ["10 OCT 08:40"]],
["Time[]{2017-10-10 21:15 (X/X)}", "2017-09-19T09:55", ["10 OCT 09:15"]],
["Time[]{2017-10-10 22:30 (X/X)}", "2017-09-19T09:55", ["10 OCT 10:30"]],
["Time[]{2017-10-10 23:35 (X/X)}", "2017-09-09T06:12", ["10 OCT 11:35"]],
["Time[]{2018-01-11 17:35 (X/X)}", "2017-12-30T15:14", ["11 JAN 17:35"]],
["Time[]{2018-01-11 18:10 (X/X)}", "2017-12-30T15:14", ["11 JAN 18:10"]],
["Time[]{2018-01-11 19:55 (X/X)}", "2017-12-30T15:14", ["11 JAN 19:55"]],
["Time[]{2018-01-11 21:50 (X/X)}", "2017-12-30T15:14", ["11 JAN 21:50"]],
["Time[]{2017-10-11 17:00 (X/X)}", "2017-09-09T06:12", ["11 OCT 17:00"]],
["Time[]{2017-09-11 13:15 (X/X)}", "2017-09-09T06:12", ["11 SEP 13:15"]],
["Time[]{2017-09-11 16:05 (X/X)}", "2017-09-09T06:12", ["11 SEP 16:05"]],
["Time[]{2018-01-12 15:15 (X/X)}", "2017-12-30T15:14", ["12 JAN 15:15"]],
["Time[]{2018-01-12 17:05 (X/X)}", "2017-12-30T15:14", ["12 JAN 17:05"]],
["Time[]{2018-01-12 19:45 (X/X)}", "2017-12-30T15:14", ["12 JAN 19:45"]],
["Time[]{2017-09-12 17:00 (X/X)}", "2017-09-09T06:12", ["12 SEP 17:00"]],
["Time[]{2017-09-12 17:55 (X/X)}", "2017-09-09T06:12", ["12 SEP 17:55"]],
["Time[]{2018-02-13 19:45 (X/X)}", "2017-10-16T13:34", ["13 FEB 07:45"]],
["Time[]{2018-02-13 20:35 (X/X)}", "2017-10-16T13:34", ["13 FEB 08:35"]],
["Time[]{2018-02-13 18:05 (X/X)}", "2017-10-16T13:34", ["13 FEB 18:05"]],
["Time[]{2018-02-13 18:50 (X/X)}", "2017-10-16T13:34", ["13 FEB 18:50"]],
["Time[]{2017-11-15 16:30 (X/X)}", "2017-11-14T04:09", ["15 NOV 16:30"]],
["Time[]{2017-11-15 17:35 (X/X)}", "2017-11-14T04:09", ["15 NOV 17:35"]],
["Time[]{2017-11-15 18:15 (X/X)}", "2017-11-14T04:09", ["15 NOV 18:15"]],
["Time[]{2018-04-15 19:10 (X/X)}", "2018-03-29T09:26", ["15 APRIL 19:10"]],
["Time[]{2016-03-03 18:55 (X/X)}", "2016-02-17T10:04", ["03 Mar 18:55"]],
["Time[]{2016-03-03 22:55 (X/X)}", "2016-02-17T10:04", ["03 Mar 22:55"]],
["Time[]{2016-03-04 00:45 (X/X)}", "2016-02-17T10:04", ["04 Mar 00:45"]],
["Time[]{2016-03-04 16:55 (X/X)}", "2016-02-17T10:04", ["04 Mar 16:55"]],
["Time[]{2016-03-09 20:30 (X/X)}", "2016-03-01T23:13", ["09 Mar 20:30"]],
["Time[]{2016-03-10 21:15 (X/X)}", "2016-03-01T23:13", ["10 Mar 21:15"]],
["Time[]{2016-02-15 19:25 (X/X)}", "2016-02-10T16:38", ["15 Feb 19:25"]],
["Time[]{2016-02-16 20:15 (X/X)}", "2016-02-10T16:38", ["16 Feb 08:15"]],
["Time[]{2016-02-16 13:05 (X/X)}", "2016-02-10T16:38", ["16 Feb 13:05"]],
["Time[]{2016-02-18 20:55 (X/X)}", "2016-02-10T16:38", ["18 Feb 20:55"]],
["Time[]{2016-02-18 22:15 (X/X)}", "2016-02-10T16:38", ["18 Feb 22:15"]],
["Time[]{2016-03-18 20:45 (X/X)}", "2016-03-04T13:34", ["18 Mar 20:45"]],
["Time[]{2017-12-12 22:30 (X/X)}", "2017-11-29T15:28", ["12 Dec 1030"]],
["Time[]{2018-03-12 22:05 (X/X)}", "2018-02-28T11:22", ["12 Mar 1005"]],
["Time[]{2017-05-12 21:00 (X/X)}", "2017-05-09T18:51", ["12 May 0900"]],
["Time[]{2017-05-12 22:15 (X/X)}", "2017-05-09T18:51", ["12 May 1015"]],
["Time[]{2017-05-12 17:00 (X/X)}", "2017-05-09T18:51", ["12 May 1700"]],
["Time[]{2017-05-12 18:15 (X/X)}", "2017-05-09T18:51", ["12 May 1815"]],
["Time[]{2017-11-12 20:20 (X/X)}", "2017-08-25T12:23", ["12 Nov 2020"]],
["Time[]{2017-11-12 22:55 (X/X)}", "2017-08-25T12:23", ["12 Nov 2255"]],
["Time[]{2017-11-13 20:20 (X/X)}", "2017-08-25T12:23", ["13 Nov 2020"]],
["Time[]{2017-11-13 22:55 (X/X)}", "2017-08-25T12:23", ["13 Nov 2255"]],
["Time[]{2017-11-13 23:30 (X/X)}", "2017-08-25T12:23", ["13 Nov 2330"]],
["Time[]{2017-12-14 22:20 (X/X)}", "2017-11-29T15:28", ["14 Dec 1020"]],
["Time[]{2017-05-14 19:05 (X/X)}", "2017-05-03T12:01", ["14 May 0705pm"]],
["Time[]{2017-07-27 23:00 (X/X)}", "2017-07-20T15:50", ["27 July 1100"]],
["Time[]{2017-10-04 14:55 (X/X)}", "2017-08-04T07:06", ["04 October 02:55"]],
["Time[]{2017-10-04 12:00 (X/X)}", "2017-08-04T07:06", ["04 October 12.00"]],
["Time[]{2018-03-02 12:50 (X/X)}", "2018-02-05T13:59", ["02 March 12:50"]],
["Time[]{2017-08-10 17:00 (X/X)}", "2017-07-14T06:23", ["10 August 17:00"]],
["Time[]{2018-03-10 19:40 (X/X)}", "2018-02-23T09:15", ["10 March 1940"]],
["Time[]{2018-03-13 17:00 (X/X)}", "2018-02-23T09:15", ["13 March 1700"]],
["Time[]{2016-02-15 20:15 (X/X)}", "2016-02-13T08:17", ["15 feb 08:15"]],
["Time[]{2016-02-15 21:30 (X/X)}", "2016-02-13T08:17", ["15 feb 09:30"]],
["Time[]{2016-02-15 22:15 (X/X)}", "2016-02-13T08:17", ["15 feb 10:15"]],
[
"Interval[]{2017-12-12 X:X (X/X) - 2017-12-13 X:X (X/X)}",
"2017-10-25T13:27",
["12- 13.12.17"],
],
[
"Interval[]{2018-01-15 X:X (X/X) - 2018-01-17 X:X (X/X)}",
"2017-12-04T15:01",
["15-17.01.2018"],
],
[
"Interval[]{2017-05-02 X:X (X/X) - 2017-05-04 X:X (X/X)}",
"2017-04-28T13:07",
["02. - 04.05. 2017", "02. - 04.05. 2017"],
],
[
"Interval[]{2017-11-16 X:X (X/X) - 2017-11-17 X:X (X/X)}",
"2017-09-18T15:23",
["16. - 17.11.17"],
],
[
"Interval[]{2017-08-03 X:X (X/X) - 2017-08-04 X:X (X/X)}",
"2017-06-29T12:25",
["03. - 04.08.2017"],
],
[
"Interval[]{2017-09-03 X:X (X/X) - 2017-09-05 X:X (X/X)}",
"2017-04-03T14:57",
["03. - 05.09.2017"],
],
[
"Interval[]{2017-07-13 X:X (X/X) - 2017-07-14 X:X (X/X)}",
"2017-05-31T09:03",
["13. - 14.07.2017"],
],
["Time[]{2016-05-20 18:55 (X/X)}", "2016-04-18T09:08", ["20. may 18:55"]],
["Time[]{2017-05-16 19:30 (X/X)}", "2017-05-08T12:11", ["16. may 19:30"]],
["Time[]{2017-10-21 23:30 (X/X)}", "2017-07-07T08:26", ["21. Oct 11:30"]],
["Time[]{2017-10-21 19:00 (X/X)}", "2017-07-07T08:26", ["21. Oct 19:00"]],
["Time[]{2017-10-21 20:04 (X/X)}", "2017-07-07T08:26", ["21. Oct 20:04"]],
["Time[]{2017-07-19 20:39 (X/X)}", "2017-07-03T16:28", ["19. Juli 8:39"]],
["Time[]{2017-03-07 17:20 (X/X)}", "2017-02-17T10:35", ["07. M\u00e4rz 17:20 Uhr"]],
["Time[]{2018-03-12 22:50 (X/X)}", "2018-03-09T13:29", ["12. M\u00e4rz 10:50"]],
["Time[]{2018-03-12 12:05 (X/X)}", "2018-03-09T13:29", ["12. M\u00e4rz 12:05"]],
["Time[]{2018-03-13 23:15 (X/X)}", "2018-03-08T15:14", ["13. M\u00e4rz 11:15"]],
["Time[]{2018-03-13 14:40 (X/X)}", "2018-03-08T15:14", ["13. M\u00e4rz 14:40"]],
["Time[]{2018-03-14 19:00 (X/X)}", "2018-03-09T13:29", ["14. M\u00e4rz 07:00"]],
["Time[]{2018-03-14 22:10 (X/X)}", "2018-03-09T13:29", ["14. M\u00e4rz 10:10"]],
["Time[]{2018-03-15 20:40 (X/X)}", "2018-03-08T15:14", ["15. M\u00e4rz 08:40"]],
["Time[]{2018-03-15 22:15 (X/X)}", "2018-03-08T15:14", ["15. M\u00e4rz 10:15"]],
["Time[]{2017-08-31 16:40 (X/X)}", "2017-07-20T10:17", ["31. August 4:40PM"]],
["Time[]{2018-01-10 19:00 (X/X)}", "2018-01-05T06:09", ["10. Januar 7:00"]],
["Time[]{2018-02-27 18:00 (X/X)}", "2018-02-12T10:09", ["27. Februar 18 Uhr"]],
["Time[]{2018-04-10 18:55 (X/X)}", "2018-03-29T14:48", ["10. April 06:55"]],
["Time[]{2018-01-11 20:20 (X/X)}", "2018-01-05T06:09", ["11. Januar 20:20"]],
["Time[]{2016-11-11 13:20 (X/X)}", "2016-10-11T07:13", ["11. November 13:20"]],
["Time[]{2016-11-11 14:50 (X/X)}", "2016-10-11T07:13", ["11. November 14:50"]],
["Time[]{2018-09-11 17:10 (X/X)}", "2018-03-20T12:49", ["11. September 17:10"]],
["Time[]{2018-04-16 23:25 (X/X)}", "2018-04-03T11:50", ["16. April 11:25"]],
["Time[]{2018-04-16 15:25 (X/X)}", "2018-04-03T11:50", ["16. April 15:25"]],
["Time[]{2015-12-16 17:10 (X/X)}", "2015-12-10T16:58", ["16. Dezember 05:10"]],
["Time[]{2015-12-16 18:20 (X/X)}", "2015-12-10T16:58", ["16. Dezember 06:20"]],
["Time[]{2018-02-19 19:45 (X/X)}", "2018-02-14T09:50", ["19. Februar 07:45"]],
["Time[]{2018-02-19 12:40 (X/X)}", "2018-02-14T09:50", ["19. Februar 12:40"]],
["Time[]{2017-01-19 22:35 (X/X)}", "2017-01-16T16:46", ["19. Januar 10:35"]],
["Time[]{2018-04-20 15:30 (X/X)}", "2018-04-03T11:50", ["20. April 15:30"]],
["Time[]{2018-04-20 17:50 (X/X)}", "2018-04-03T11:50", ["20. April 17:50"]],
["Time[]{2018-09-11 20:15 (X/X)}", "2018-03-20T12:49", ["11. September 08:15 Uhr"]],
["Time[]{2017-12-12 14:00 (X/X)}", "2017-12-07T09:10", ["12. Dezember 14:00 Uhr"]],
["Time[]{2017-12-12 20:50 (X/X)}", "2017-12-07T09:10", ["12. Dezember 20:50 Uhr"]],
["Time[]{2017-04-04 17:35 (X/X)}", "2017-03-25T14:11", ["04. April 17:35 h"]],
["Time[]{2018-04-25 22:15 (X/X)}", "2018-03-21T12:49", ["25. apr 10:15"]],
[
"Interval[]{2018-12-12 X:X (X/X) - 2018-12-14 X:X (X/X)}",
"2018-03-22T15:20",
["12. bis 14.12.2018"],
],
["Time[]{2018-03-13 21:20 (X/X)}", "2018-03-06T11:02", ["13. mar 09:20"]],
[
"Interval[]{2018-01-24 X:X (X/X) - 2018-01-29 X:X (X/X)}",
"2017-12-18T13:03",
["24.-29. Januar 2018"],
],
[
"Interval[]{2018-03-21 X:X (X/X) - 2018-03-23 X:X (X/X)}",
"2018-01-09T09:14",
["21.-23.3.18"],
],
[
"Interval[]{2017-04-10 X:X (X/X) - 2017-04-11 X:X (X/X)}",
"2017-04-04T08:53",
["10.-11.04. 2017", "10.-11.04.2017", "10.-11.04. 2017"],
],
[
"Interval[]{2017-11-05 X:X (X/X) - 2017-11-10 X:X (X/X)}",
"2017-08-14T16:01",
["05.-10.11.17"],
],
[
"Interval[]{2018-05-07 X:X (X/X) - 2018-05-09 X:X (X/X)}",
"2018-02-28T17:28",
["07.-09.05.18"],
],
[
"Interval[]{2017-10-07 X:X (X/X) - 2017-10-14 X:X (X/X)}",
"2017-08-07T08:13",
["07.-14.10.17"],
],
[
"Interval[]{2018-05-04 X:X (X/X) - 2018-05-05 X:X (X/X)}",
"2018-02-02T09:44",
["04.-05.05.2018"],
],
[
"Interval[]{2017-11-05 X:X (X/X) - 2017-11-07 X:X (X/X)}",
"2017-09-19T12:19",
["05.-07.11.2017"],
],
[
"Interval[]{2018-02-05 X:X (X/X) - 2018-02-10 X:X (X/X)}",
"2017-09-26T14:05",
["05.-10.02.2018"],
],
[
"Interval[]{2018-02-05 X:X (X/X) - 2018-02-11 X:X (X/X)}",
"2017-09-26T14:05",
["05.-11.02.2018"],
],
[
"Interval[]{2017-03-06 X:X (X/X) - 2017-03-08 X:X (X/X)}",
"2017-01-19T08:09",
["06.-08.03.2017"],
],
[
"Interval[]{2018-05-06 X:X (X/X) - 2018-05-09 X:X (X/X)}",
"2018-02-07T12:30",
["06.-09.05.2018"],
],
[
"Interval[]{2018-06-08 X:X (X/X) - 2018-06-09 X:X (X/X)}",
"2018-02-02T10:04",
["08.-09.06.2018"],
],
[
"Interval[]{2018-07-08 X:X (X/X) - 2018-07-10 X:X (X/X)}",
"2018-02-07T12:30",
["08.-10.07.2018"],
],
[
"Interval[]{2018-01-08 X:X (X/X) - 2018-01-11 X:X (X/X)}",
"2017-11-16T09:10",
["08.-11.01.2018"],
],
[
"Interval[]{2018-06-10 X:X (X/X) - 2018-06-12 X:X (X/X)}",
"2018-02-07T12:30",
["10.-12.06.2018"],
],
["Time[]{2017-05-23 14:00 (X/X)}", "2017-04-25T15:59", ["23.Mai 14h"]],
[
"Interval[]{None - 2018-02-14 22:30 (X/X)}",
"2018-02-02T18:56",
["14.2 sp\u00e4testens um 10:30"],
],
[
"Interval[]{2017-03-17 22:30 (X/X) - 2017-03-18 21:25 (X/X)}",
"2017-03-09T10:17",
["17.03. 10:30 - 18.03. 09:25"],
],
[
"Interval[]{None - 2016-01-20 19:00 (X/X)}",
"2016-01-13T12:05",
["20.01. sp\u00e4testens um 19 Uhr"],
],
[
"Interval[]{None - 2017-07-03 22:00 (X/X)}",
"2017-06-21T13:36",
["03.07. sp\u00e4testens um 10:00 Uhr"],
],
[
"Interval[]{2017-08-15 13:00 (X/X) - 2017-08-15 16:30 (X/X)}",
"2017-08-02T06:54",
["15.08.17 13 - 16:30"],
],
[
"Interval[]{2017-04-05 15:00 (X/X) - 2017-04-05 17:00 (X/X)}",
"2017-04-03T11:09",
["05.04.17 15-17 Uhr"],
],
[
"Interval[]{2017-06-11 11:00 (X/X) - 2017-06-11 12:00 (X/X)}",
"2017-04-18T10:38",
["11.06.17 11-12 Uhr"],
],
[
"Interval[]{2017-06-11 11:00 (X/X) - 2017-06-11 13:00 (X/X)}",
"2017-04-04T09:18",
["11.06.17 11-13 Uhr"],
],
[
"Interval[]{2017-07-13 19:00 (X/X) - 2017-07-13 19:30 (X/X)}",
"2017-07-07T14:52",
["13.07.17 19-19:30 Uhr"],
],
[
"Time[]{2017-06-02 X:X (X/X)}",
"2017-01-23T17:51",
["02.06.17 19.30", "02.06.17 19.30"],
],
[
"Interval[]{2016-04-01 19:00 (X/X) - 2016-04-01 21:10 (X/X)}",
"2016-03-23T09:11",
["01.04.16 1900-2110"],
],
[
"Interval[]{2016-07-01 19:25 (X/X) - 2016-07-01 22:50 (X/X)}",
"2016-06-28T09:39",
["01.07.16 1925-2250"],
],
[
"Interval[]{2016-05-02 19:30 (X/X) - 2016-05-02 20:00 (X/X)}",
"2016-04-27T09:14",
["02.05.16 1930-2000"],
],
[
"Interval[]{2016-06-03 19:05 (X/X) - 2016-06-03 21:00 (X/X)}",
"2016-05-27T13:01",
["03.06.16 1905-2100"],
],
[
"Interval[]{2016-04-04 19:30 (X/X) - 2016-04-04 20:00 (X/X)}",
"2016-03-30T12:57",
["04.04.16 1930-2000"],
],
[
"Interval[]{2016-04-04 22:40 (X/X) - 2016-04-05 03:30 (X/X)}",
"2016-04-04T14:32",
["04.04.16 2240-0330am"],
],
[
"Interval[]{2016-05-06 19:00 (X/X) - 2016-05-06 21:10 (X/X)}",
"2016-04-29T12:27",
["06.05.16 1900-2110"],
],
[
"Interval[]{2016-04-07 19:00 (X/X) - 2016-04-07 21:10 (X/X)}",
"2016-04-05T08:03",
["07.04.16 1900-2110"],
],
[
"Interval[]{2016-04-08 19:00 (X/X) - 2016-04-08 21:10 (X/X)}",
"2016-04-01T13:47",
["08.04.16 1900-2110"],
],
[
"Interval[]{2016-07-08 19:05 (X/X) - 2016-07-08 21:00 (X/X)}",
"2016-06-29T09:44",
["08.07.16 1905-2100"],
],
[
"Interval[]{2016-06-09 19:00 (X/X) - 2016-06-09 21:10 (X/X)}",
"2016-06-06T09:52",
["09.06.16 1900-2110"],
],
[
"Interval[]{2016-06-10 19:25 (X/X) - 2016-06-10 22:50 (X/X)}",
"2016-06-03T07:53",
["10.06.16 1925-2250"],
],
[
"Interval[]{2016-05-13 19:00 (X/X) - 2016-05-13 21:10 (X/X)}",
"2016-05-06T10:44",
["13.05.16 1900-2110"],
],
[
"Interval[]{2016-05-13 19:30 (X/X) - 2016-05-13 20:40 (X/X)}",
"2016-05-12T16:03",
["13.05.16 1930-2040"],
],
[
"Interval[]{2016-04-15 13:00 (X/X) - 2016-04-15 16:00 (X/X)}",
"2016-04-11T13:39",
["15.04.16 von 13-16 Uhr", "15.04.16 von 13-16 Uhr"],
],
[
"Interval[]{2018-04-10 08:00 (X/X) - 2018-04-10 10:00 (X/X)}",
"2018-03-26T15:54",
["10.04.2018 8-10AM", "10.04.2018 8-10AM"],
],
[
"Interval[]{2017-04-07 17:00 (X/X) - 2017-04-07 18:00 (X/X)}",
"2017-04-03T11:09",
["07.04.2017 17-18 Uhr"],
],
[
"Time[]{2017-03-22 19:10 (X/X)}",
"2017-03-07T14:54",
["22.03.2017 19:10", "22.03.2017 19:10"],
],
[
"Time[]{2018-02-14 12:00 (X/X)}",
"2018-01-24T15:25",
["14.02.2018 morgens ca. 12.00 Uhr"],
],
# [
# "Time[]{2017-03-19 09:00 (X/X)}",
# "2017-03-03T08:57",
# ["19.03.2017 morgens gegen 09.00 h"],
# ],
["Time[]{2017-05-15 15:40 (X/X)}", "2017-04-06T09:01", ["15:40 Mon 15 May"]],
["Time[]{2017-04-09 17:20 (X/X)}", "2017-03-30T13:07", ["17:20 So 9. Apr"]],
["Time[]{2017-07-13 22:25 (X/X)}", "2017-07-05T12:39", ["10:25 Thu 13. Jul"]],
["Time[]{2017-03-22 22:35 (X/X)}", "2017-03-13T15:25", ["10:35 Mi 22. M\u00e4r"]],
["Time[]{2017-07-14 23:05 (X/X)}", "2017-07-05T12:39", ["11:05 Fri 14 Jul"]],
[
"Time[]{2017-01-11 19:05 (X/X)}",
"2017-01-03T07:56",
["19:05 Mittwoch 11 Januar"],
],
["Time[]{2016-12-02 18:50 (X/X)}", "2016-11-02T16:44", ["2 DEC 18:50"]],
["Time[]{2016-11-14 21:30 (X/X)}", "2016-10-31T15:12", ["14 NOV 9:30"]],
["Time[]{2016-12-01 22:00 (X/X)}", "2016-11-22T09:46", ["1 DEC 10:00"]],
["Time[]{2017-07-01 19:40 (X/X)}", "2017-05-19T08:51", ["1 JUL 19:40"]],
["Time[]{2016-11-02 22:15 (X/X)}", "2016-10-28T10:19", ["2 NOV 10:15"]],
["Time[]{2016-11-02 22:35 (X/X)}", "2016-10-28T08:42", ["2 NOV 10:35"]],
["Time[]{2017-10-02 22:15 (X/X)}", "2017-08-30T10:39", ["2 OCT 22:15"]],
["Time[]{2017-04-03 23:40 (X/X)}", "2017-03-15T10:47", ["3 APR 11:40"]],
["Time[]{2017-04-03 12:30 (X/X)}", "2017-03-15T10:47", ["3 APR 12:30"]],
["Time[]{2017-04-03 15:20 (X/X)}", "2017-03-15T10:47", ["3 APR 15:20"]],
["Time[]{2017-04-03 16:30 (X/X)}", "2017-03-15T10:47", ["3 APR 16:30"]],
["Time[]{2017-04-03 18:30 (X/X)}", "2017-03-06T10:53", ["3 APR 18:30"]],
["Time[]{2017-04-03 19:55 (X/X)}", "2017-03-06T10:53", ["3 APR 19:55"]],
["Time[]{2017-08-03 19:40 (X/X)}", "2017-05-19T08:51", ["3 AUG 19:40"]],
["Time[]{2016-11-03 20:00 (X/X)}", "2016-10-28T08:42", ["3 NOV 20:00"]],
["Time[]{2017-08-04 17:15 (X/X)}", "2017-05-19T08:51", ["4 AUG 17:15"]],
["Time[]{2017-08-04 18:20 (X/X)}", "2017-05-19T08:51", ["4 AUG 18:20"]],
["Time[]{2016-11-04 18:35 (X/X)}", "2016-11-02T08:55", ["4 NOV 18:35"]],
["Time[]{2017-04-06 19:40 (X/X)}", "2017-03-06T10:53", ["6 APR 07:40"]],
["Time[]{2017-04-06 21:00 (X/X)}", "2017-03-06T10:53", ["6 APR 09:00"]],
["Time[]{2017-04-06 22:00 (X/X)}", "2017-03-06T10:53", ["6 APR 10:00"]],
["Time[]{2017-04-06 13:10 (X/X)}", "2017-03-06T10:53", ["6 APR 13:10"]],
["Time[]{2017-04-07 12:55 (X/X)}", "2017-03-15T10:47", ["7 APR 12:55"]],
["Time[]{2017-04-07 14:15 (X/X)}", "2017-03-15T10:47", ["7 APR 14:15"]],
["Time[]{2017-04-07 16:10 (X/X)}", "2017-03-15T10:47", ["7 APR 16:10"]],
["Time[]{2017-04-07 17:00 (X/X)}", "2017-03-15T10:47", ["7 APR 17:00"]],
["Time[]{2017-04-07 19:20 (X/X)}", "2017-03-06T10:53", ["7 APR 19:20"]],
["Time[]{2017-04-07 20:20 (X/X)}", "2017-03-06T10:53", ["7 APR 20:20"]],
["Time[]{2017-04-07 21:00 (X/X)}", "2017-03-06T10:53", ["7 APR 21:00"]],
["Time[]{2017-04-07 22:10 (X/X)}", "2017-03-06T10:53", ["7 APR 22:10"]],
["Time[]{2016-11-09 21:00 (X/X)}", "2016-11-02T08:51", ["9 NOV 09:00"]],
["Time[]{2016-11-09 22:25 (X/X)}", "2016-11-02T08:55", ["9 NOV 10:25"]],
["Time[]{2016-11-10 16:00 (X/X)}", "2016-11-02T09:52", ["10 NOV 16:00"]],
["Time[]{2016-11-10 17:00 (X/X)}", "2016-11-08T09:06", ["10 NOV 17:00"]],
["Time[]{2016-11-10 17:30 (X/X)}", "2016-11-09T09:19", ["10 NOV 17:30"]],
["Time[]{2016-12-11 19:25 (X/X)}", "2016-11-21T10:41", ["11 DEC 19:25"]],
["Time[]{2016-11-11 23:30 (X/X)}", "2016-11-08T11:44", ["11 NOV 11:30"]],
["Time[]{2016-11-11 16:00 (X/X)}", "2016-11-08T11:44", ["11 NOV 16:00"]],
["Time[]{2016-11-11 19:00 (X/X)}", "2016-11-08T09:06", ["11 NOV 19:00"]],
["Time[]{2016-11-12 15:00 (X/X)}", "2016-11-09T15:42", ["12 NOV 15:00"]],
["Time[]{2017-10-12 00:40 (X/X)}", "2017-08-30T10:39", ["12 OCT 00:40"]],
["Time[]{2017-08-13 20:05 (X/X)}", "2017-05-19T08:51", ["13 AUG 08:05"]],
["Time[]{2017-08-13 21:10 (X/X)}", "2017-05-19T08:51", ["13 AUG 09:10"]],
["Time[]{2017-08-13 13:30 (X/X)}", "2017-05-19T08:51", ["13 AUG 13:30"]],
["Time[]{2017-08-13 17:40 (X/X)}", "2017-05-19T08:51", ["13 AUG 17:40"]],
["Time[]{2017-09-15 21:25 (X/X)}", "2017-08-18T14:19", ["15th September 21:25"]],
["Time[]{2018-03-22 19:50 (X/X)}", "2018-02-09T14:33", ["22 mar 7:50"]],
[
"Time[]{2018-03-23 13:50 (X/X)}",
"2018-02-09T14:33",
["23 march 13:50", "Friday 23rd Mar 13:50"],
],
["Time[]{2018-03-02 07:10 (X/X)}", "2018-02-09T09:04", ["2 mar 7:10am"]],
[
"Time[]{2018-04-17 X:X (X/X)}",
"2018-04-12T11:16",
["on Tue, 17-Apr", "on Tue, 17-Apr"],
],
[
"Time[]{2017-03-12 X:X (X/X)}",
"2016-11-14T20:44",
["on Sunday March 12", "on Sunday March 12"],
],
[
"Time[]{2016-12-13 X:X (X/X)}",
"2016-11-15T15:03",
["on Tuesday 13 December", "16-12-13", "on Tuesday 13 December"],
],
[
"Time[]{2017-08-25 X:X (X/X)}",
"2017-08-02T08:35",
["am Freitag 25. August", "am Freitag 25. August"],
],
[
"Time[]{2017-04-14 X:X (X/X)}",
"2017-04-06T15:11",
["am Freitag 14.4.", "am Freitag 14.4."],
],
["Time[]{2018-01-11 15:45 (X/X)}", "2018-01-08T17:30", ["Thursday 15:45"]],
[
"Time[]{2017-11-21 X:X (X/X)}",
"2017-11-05T14:30",
["am Dienstag 21.11.", "am Dienstag 21.11."],
],
[
"Time[]{2016-11-10 X:X (X/X)}",
"2016-10-31T00:53",
["am Donnerstag 10.11.", "am Donnerstag 10.11."],
],
[
"Time[]{2017-11-23 X:X (X/X)}",
"2017-11-05T14:30",
["am Donnerstag 23.11.", "am Donnerstag 23.11.", "Donnerstag 23. November"],
],
[
"Time[]{2016-11-24 X:X (X/X)}",
"2016-10-19T16:28",
["am Donnerstag 24.11.", "am Donnerstag 24.11."],
],
[
"Time[]{2017-08-22 18:40 (X/X)}",
"2017-08-10T09:17",
["am Dienstag 22.08. 18:40", "am Dienstag 22.08. 18:40"],
],
["Time[]{2016-01-17 X:X (X/X)}", "2016-12-16T08:38", ["am Dienstag 17.01.2016"]],
["Time[]{2018-06-28 X:X (X/X)}", "2018-03-23T09:58", ["am Donnerstag 28.06.2018"]],
[
"Time[]{2017-09-22 X:X (X/X)}",
"2017-09-11T16:52",
["on Friday 22/9", "on Friday 22/9"],
],
[
"Time[]{2018-01-31 20:40 (X/X)}",
"2018-01-25T13:54",
["on Wednesday 31/1 at 08:40", "on Wednesday 31/1 at 08:40"],
],
[
"Time[]{2017-08-27 X:X (X/X)}",
"2017-08-17T10:25",
["am Sonntag 27/08", "am Sonntag 27/08"],
],
["Time[]{2016-05-11 14:30 (X/X)}", "2016-05-09T20:05", ["am Mittwoch 14:30"]],
["Time[]{2016-02-18 15:55 (X/X)}", "2016-02-16T10:31", ["am Donnerstag 15:55 Uhr"]],
["Time[]{2018-04-30 X:X (X/X)}", "2018-01-25T13:40", ["on Monday 30th April"]],
[
"Time[]{2017-07-09 X:X (X/X)}",
"2017-06-28T08:23",
["on Sunday 9th July", "on Sunday 9th July"],
],
[
"Time[]{2017-03-08 X:X (X/X)}",
"2017-02-28T16:22",
["am Mittwoch den 08.03.", "am Mittwoch den 08.03."],
],
[
"Time[]{2016-09-01 X:X (X/X)}",
"2016-06-06T14:31",
["am Donnerstag, 01. September", "am Donnerstag, 01. September"],
],
[
"Time[]{2018-04-10 X:X (X/evening)}",
"2018-03-20T08:03",
["am Dienstag, 10.4. abends", "am Dienstag, 10.4. abends"],
],
[
"Time[]{2017-08-18 X:X (X/X)}",
"2017-08-09T06:58",
["am Freitag 18.08", "am Freitag 18.08"],
],
[
"Time[]{2017-09-27 06:30 (X/X)}",
"2017-09-20T17:50",
["am Mittwoch 27.09. 06:30am", "am Mittwoch 27.09. 06:30am"],
],
["Time[]{2017-03-21 X:X (X/X)}", "2017-03-13T08:37", ["am Dienstag 21.03.17"]],
["Time[]{2016-11-29 X:X (X/X)}", "2016-10-20T15:40", ["am Dienstag 29.11.16"]],
["Time[]{2017-03-16 X:X (X/X)}", "2017-03-07T11:26", ["am Donnerstag 16.03.17"]],
["Time[]{2017-06-22 X:X (X/X)}", "2017-05-05T10:43", ["am Donnerstag 22.06.17"]],
["Time[]{2018-02-02 X:X (X/X)}", "2018-01-22T14:32", ["am Freitag 02.02.2018"]],
["Time[]{2015-11-20 X:X (X/X)}", "2015-11-06T09:36", ["am Freitag 20.11.2015"]],
[
"Time[]{2016-11-07 X:X (X/X)}",
"2016-11-04T09:55",
["ab Montag den 07.11", "ab Montag den 07.11"],
],
[
"Time[]{2015-10-06 X:X (X/X)}",
"2015-09-24T10:40",
["am Dienstag den 06.10.", "am Dienstag den 06.10."],
],
[
"Time[]{2017-08-15 X:X (X/X)}",
"2017-08-03T12:00",
["am Dienstag den 15.08.", "am Dienstag den 15.08."],
],
[
"Time[]{2017-12-09 13:00 (X/X)}",
"2017-11-27T14:14",
["um 13 Uhr Samstag 09.12.2017"],
],
[
"Interval[]{2017-12-13 16:00 (X/X) - None}",
"2017-12-04T09:06",
["am 13.12. ab frühestens 16:00 h", "am 13.12. ab frühestens 16:00 h"],
],
[
"Interval[]{None - 2018-03-22 20:00 (X/X)}",
"2018-03-09T12:27",
["am 22.03. sp\u00e4testens um 8.00 Uhr"],
],
[
"Interval[]{None - 2017-05-16 13:00 (X/X)}",
"2017-05-05T08:14",
["am 16.05. sp\u00e4testens um 13 Uhr"],
],
[
"Interval[]{None - 2017-07-10 19:30 (X/X)}",
"2017-05-30T12:02",
["am 10.07. sp\u00e4testens um 07:30"],
],
[
"Interval[]{2017-04-12 19:00 (X/X) - None}",
"2017-04-05T12:42",
["am 12.04.2017 ab ca. 7.00 Uhr"],
],
[
"Time[]{2016-10-12 16:00 (X/X)}",
"2016-09-22T10:28",
["am 12.10.2016 nachmittags 16.00 Uhr", "am 12.10.2016 nachmittags 16.00 Uhr"],
],
# [
# "Time[]{2015-10-21 06:55 (X/X)}",
# "2015-10-14T14:32",
# ["am 21.10.2015 fr\u00fch 06:55", "am 21.10.2015 fr\u00fch 06:55"],
# ],
[
"Time[]{2016-11-10 17:20 (X/X)}",
"2016-10-19T12:53",
["am 10.11.2016 abends 17:20 Uhr", "am 10.11.2016 abends 17:20 Uhr"],
],
# [
# "Time[]{2018-02-01 18:48 (X/X)}",
# "2018-01-22T07:58",
# ["am 01.02.2018 morgens um 06.48 Uhr"],
# ],
# [
# "Time[]{2017-02-09 23:00 (X/X)}",
# "2017-01-27T07:41",
# ["am 09.02.2017 vormittags um 11:00 Uhr"],
# ],
[
"Time[]{2017-06-01 19:00 (X/X)}",
"2017-03-28T08:06",
["am 01.06.2017 abends ca. 19.00 Uhr"],
],
[
"Time[]{2017-04-12 18:00 (X/X)}",
"2017-04-05T12:42",
["am 12.04.2017 abends ca. 18.00 Uhr"],
],
[
"Time[]{2016-11-08 20:00 (X/X)}",
"2016-10-28T07:29",
["am 08.11.2016 abends gegen 20 Uhr"],
],
[
"Time[]{2017-05-30 20:20 (X/X)}",
"2017-05-11T11:58",
["um 08:20 Uhr Dienstag 30.05.2017"],
],
[
"Interval[]{2018-03-26 X:X (X/X) - 2018-03-29 X:X (X/X)}",
"2018-03-14T14:42",
["ab den 26.03.2018-29.03.2018", "ab den 26.03.2018-29.03.2018"],
],
[
"Time[]{2015-10-22 X:X (X/evening)}",
"2015-10-19T15:13",
["am kommenden Donnerstag abends", "am kommenden Donnerstag abends"],
],
[
"Time[]{2018-05-28 14:05 (X/X)}",
"2018-04-10T20:29",
["on Monday 28.05.2018 14:05"],
],
[
"Interval[]{2017-06-02 X:X (X/X) - 2017-06-03 X:X (X/X)}",
"2017-04-28T10:53",
["vom 02. - 03.06.2017"],
],
[
"Interval[]{2017-05-08 X:X (X/X) - 2017-05-10 X:X (X/X)}",
"2017-03-29T06:38",
["vom 08. - 10.05.2017"],
],
[
"Interval[]{2018-04-08 X:X (X/X) - 2018-04-14 X:X (X/X)}",
"2018-01-12T10:02",
["vom 08. - 14.04.2018"],
],
[
"Interval[]{2017-09-15 X:X (X/X) - 2017-09-16 X:X (X/X)}",
"2017-08-14T13:04",
["vom 15. auf den 16.09.2017"],
],
[
"Interval[]{2017-02-01 X:X (X/X) - 2017-02-03 X:X (X/X)}",
"2016-11-30T20:38",
["vom 01.-03. Februar 2017"],
],
[
"Interval[]{2017-03-14 X:X (X/X) - 2017-03-16 X:X (X/X)}",
"2016-01-18T07:24",
["vom 14.-16.3.2017"],
],
[
"Interval[]{2018-06-05 X:X (X/X) - 2018-06-06 X:X (X/X)}",
"2018-02-28T10:20",
["vom 05.-06.06.18"],
],
[
"Interval[]{2017-11-08 X:X (X/X) - 2017-11-09 X:X (X/X)}",
"2017-10-06T14:27",
["vom 08.-09.11.2017"],
],
[
"Interval[]{2017-05-08 X:X (X/X) - 2017-05-12 X:X (X/X)}",
"2016-09-02T08:40",
["vom 08.-12.05.2017"],
],
[
"Interval[]{2018-03-09 X:X (X/X) - 2018-03-11 X:X (X/X)}",
"2018-01-08T08:51",
["vom 09.-11.03.2018"],
],
[
"Interval[]{2018-01-09 X:X (X/X) - 2018-01-12 X:X (X/X)}",
"2017-11-15T13:15",
["vom 09.-12.01.2018"],
],
[
"Interval[]{2018-03-09 X:X (X/X) - 2018-03-12 X:X (X/X)}",
"2018-01-08T08:51",
["vom 09.-12.03.2018"],
],
[
"Time[]{2016-09-02 X:X (X/morning)}",
"2016-09-01T07:53",
["morgen Freitagvormittag", "morgen Freitagvormittag"],
],
[
"Time[]{2017-12-21 19:03 (X/X)}",
"2017-12-14T08:21",
["thursday next week 7:03pm"],
],
[
"Time[]{2017-12-21 15:25 (X/X)}",
"2017-12-14T08:21",
["thursday next week 15:25"],
],
[
"Time[]{2017-09-12 17:44 (X/X)}",
"2017-09-07T07:51",
["n\u00e4chste Woche Dienstag 17:44"],
],
["Time[]{2018-01-29 21:15 (X/X)}", "2018-01-22T12:56", ["next Monday 9:15"]],
["Time[]{2016-06-30 19:05 (X/X)}", "2016-06-28T11:00", ["diesen Donnerstag 7:05"]],
[
"Time[]{2017-06-19 21:30 (X/X)}",
"2017-06-16T11:26",
["kommenden Montag 9:30 Uhr"],
],
["Time[]{2017-01-08 14:00 (X/X)}", "2017-01-04T16:49", ["diesen Sonntag 14 Uhr"]],
["Time[]{2017-09-28 22:00 (X/X)}", "2017-09-26T16:18", ["diesen Donnerstag 10:00"]],
["Time[]{2017-10-11 18:39 (X/X)}", "2017-10-11T07:28", ["heute Abend um 18:39"]],
[
"Time[]{2017-03-23 16:36 (X/X)}",
"2017-03-22T09:18",
["morgen Nachmittag um 16:36 Uhr"],
],
[
"Time[]{2016-10-11 X:X (X/evening)}",
"2016-10-06T09:06",
["kommenden Dienstag abends", "kommenden Dienstag abends"],
],
[
"Time[]{2016-10-11 X:X (X/morning)}",
"2016-10-06T09:06",
["kommenden Dienstag morgens"],
],
[
"Time[]{2017-09-21 20:30 (X/X)}",
"2017-09-18T13:35",
["diesen Donnerstag 21.09 08:30 Uhr", "diesen Donnerstag 21.09. 08:30 Uhr"],
],
[
"Time[]{2018-01-23 X:X (X/X)}",
"2018-01-22T13:41",
["morgen 23.01", "morgen 23.01"],
],
[
"Interval[]{2017-01-18 X:X (X/X) - 2017-01-20 X:X (X/X)}",
"2017-01-18T12:52",
["heute bis Freitag"],
],
["Time[]{2016-12-09 21:45 (X/X)}", "2016-12-02T13:36", ["next week Fri 0945"]],
[
"Time[]{2016-10-19 21:20 (X/X)}",
"2016-10-17T09:55",
["this wednesday 19th 09:20", "this wednesday 09:20"],
],
[
"Interval[]{2017-06-14 18:00 (X/X) - None}",
"2017-05-24T11:13",
["Am 14.06.2017 fr\u00fchestens 18:00 Uhr"],
],
["Time[]{2017-03-07 X:X (X/X)}", "2017-03-06T13:23", ["Di. 07."]],
["Time[]{2016-09-13 X:X (X/X)}", "2016-09-12T20:07", ["Di. 13.09"]],
["Time[]{2017-02-14 X:X (X/X)}", "2017-02-13T15:54", ["Di. 14.02"]],
[
"Interval[]{2017-09-26 X:X (X/X) - 2017-09-27 X:X (X/X)}",
"2017-08-31T16:34",
["Di., 26.09.-27.09., 1 Nacht"],
],
[
"Interval[]{2018-02-23 X:X (X/X) - 2018-02-24 X:X (X/X)}",
"2018-02-14T16:04",
["Fr.-Sa., 23.02.-24.02., 1 Nacht"],
],
["Time[]{2016-12-03 X:X (X/X)}", "2016-11-30T13:23", ["Samstag 3.12"]],
["Time[]{2016-10-14 X:X (X/X)}", "2016-10-09T08:56", ["Friday 14"]],
["Time[]{2016-10-11 X:X (X/X)}", "2016-10-04T10:52", ["Tuesday 11"]],
["Time[]{2017-07-18 X:X (X/X)}", "2017-07-06T12:42", ["Dienstag 18.7."]],
["Time[]{2016-06-28 X:X (X/X)}", "2016-06-13T08:26", ["Dienstag 28.6."]],
["Time[]{2017-06-15 X:X (X/X)}", "2017-06-07T11:25", ["Donnerstag 15.6."]],
["Time[]{2017-07-20 X:X (X/X)}", "2017-07-12T20:49", ["Donnerstag 20.7."]],
["Time[]{2017-08-17 16:15 (X/X)}", "2017-08-10T09:11", ["Donnerstag 17.8. 16:15"]],
["Time[]{2018-01-23 X:X (X/evening)}", "2018-01-23T10:48", ["Abends 23.01"]],
[
"Time[]{2018-04-03 X:X (X/X)}",
"2018-03-29T10:31",
["Dienstag 03.04", "Dienstag 03.04"],
],
[
"Time[]{2017-06-20 X:X (X/X)}",
"2017-06-19T07:04",
["Dienstag 20.6", "Dienstag 20.6", "am Dienstag 20.6"],
],
["Time[]{2017-03-02 X:X (X/X)}", "2017-02-13T11:00", ["Donnerstag 02.03"]],
["Time[]{2017-12-07 X:X (X/X)}", "2017-11-27T10:53", ["Donnerstag 07.12"]],
["Time[]{2017-08-02 X:X (X/X)}", "2017-07-10T07:29", ["Mittwoch 02.08"]],
["Time[]{2017-06-07 X:X (X/X)}", "2017-06-04T20:23", ["Mittwoch 07.06"]],
["Time[]{2017-12-13 X:X (X/X)}", "2017-12-07T13:33", ["Mittwoch 13.12"]],
[
"Time[]{2017-08-23 X:X (X/X)}",
"2017-08-16T13:00",
["Mittwoch 23.08", "Dienstag 23.08", "am Mittwoch 23.08"],
],
["Time[]{2017-10-25 X:X (X/X)}", "2017-10-10T12:06", ["Mittwoch 25.10"]],
["Time[]{2017-09-11 X:X (X/X)}", "2017-09-08T20:54", ["Monday 11.09"]],
["Time[]{2017-06-19 X:X (X/X)}", "2017-05-24T08:15", ["Monday 19.06"]],
["Time[]{2018-03-15 X:X (X/X)}", "2018-01-23T11:31", ["Donnerstag 15.03."]],
["Time[]{2018-04-04 X:X (X/X)}", "2018-03-27T08:41", ["Mittwoch 4.4."]],
[
"Time[]{2016-09-23 X:X (X/X)}",
"2016-09-20T08:45",
["Freitag, 23. September 2016"],
],
["Time[]{2017-07-25 X:X (X/X)}", "2017-05-30T09:59", ["Dienstag 25.07"]],
["Time[]{2017-08-17 X:X (X/X)}", "2017-08-09T08:02", ["Donnerstag 17.08"]],
[
"Interval[]{2017-10-05 21:45 (X/X) - 2017-10-05 22:55 (X/X)}",
"2017-09-28T07:55",
["Donnerstag, den 5.10.2017 09:45 - 10:55 Uhr"],
],
["Time[]{2018-01-07 X:X (X/X)}", "2017-12-19T09:24", ["7. Januar 2018"]],
["Time[]{2017-10-26 X:X (X/X)}", "2017-10-17T18:14", ["26 Oct 2017"]],
["Time[]{2018-05-24 14:55 (X/X)}", "2018-04-10T08:46", ["24 of May at 14:55"]],
["Time[]{2018-04-25 12:00 (X/X)}", "2018-04-05T09:18", ["25 of April at 12:00"]],
["Time[]{2017-05-22 X:X (X/X)}", "2017-05-04T16:28", ["22. Mai 2017"]],
["Time[]{2016-07-15 X:X (X/X)}", "2016-06-20T10:03", ["15. Juli 16"]],
["Time[]{2018-06-14 X:X (X/X)}", "2018-03-08T11:34", ["14. Juni 2018"]],
["Time[]{2018-02-14 X:X (X/X)}", "2017-12-19T09:24", ["14. Februar 2018"]],
["Time[]{2018-03-14 X:X (X/X)}", "2018-03-12T16:48", ["14. 03."]],
[
"Interval[]{2018-04-10 X:X (X/X) - 2018-04-11 X:X (X/X)}",
"2018-04-05T10:08",
["10.04. - 11.04., 1 Nacht"],
],
["Time[]{2018-01-18 15:30 (X/X)}", "2018-01-18T13:11", ["18.01. 15:30 Uhr"]],
[
"Interval[]{2017-10-06 X:X (X/X) - 2017-10-07 X:X (X/X)}",
"2017-09-22T12:53",
["06.10.-07.10., 1 Nacht"],
],
[
"Interval[]{2017-12-06 X:X (X/X) - 2017-12-07 X:X (X/X)}",
"2017-11-24T14:27",
["06.12.2017 to 07.12.2017 (1 night"],
],
[
"Interval[]{2018-03-09 21:00 (X/X) - 2018-03-09 22:00 (X/X)}",
"2018-02-20T09:37",
["09.03.2018 ca. 9-10 Uhr"],
],
[
"Interval[]{2017-07-06 14:00 (X/X) - 2017-07-06 15:00 (X/X)}",
"2017-06-21T12:02",
["06.07.2017 ca. 14-15 Uhr"],
],
["Time[]{2017-09-15 14:35 (X/X)}", "2017-08-11T13:10", ["02:35 Friday 15 Sep 2017"]],
["Time[]{2017-09-15 19:20 (X/X)}", "2017-08-11T13:10", ["07:20 Friday 15 Sep 2017"]],
[
"Time[]{2016-11-11 22:00 (X/X)}",
"2016-11-09T13:16",
["10:00 Fri 11 Nov 2016"],
],
[
"Time[]{2018-05-09 16:00 (X/X)}",
"2018-03-26T11:11",
["04:00 Wednesday 9 May 2018"],
],
[
"Time[]{2018-05-09 20:40 (X/X)}",
"2018-03-26T11:11",
["08:40 Wednesday 9 May 2018"],
],
[
"Time[]{2018-03-01 20:30 (X/X)}",
"2018-02-19T15:04",
["08:30 Thursday 1 March 2018"],
],
[
"Time[]{2018-05-12 17:00 (X/X)}",
"2018-03-26T11:11",
["05:00 Saturday 12 May 2018"],
],
[
"Time[]{2018-05-12 19:45 (X/X)}",
"2018-03-26T11:11",
["07:45 Saturday 12 May 2018"],
],
[
"Time[]{2018-05-12 22:25 (X/X)}",
"2018-03-26T11:11",
["10:25 Saturday 12 May 2018"],
],
[
"Time[]{X-X-X 22:00 (X/X)}",
"2022-12-08T11:11",
["at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10", "at 10"],
],
[
"Time[]{X-X-X 16:00 (X/X)}",
"2022-12-08T11:11",
["at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", "at 4", ],
],
[
"Time[]{2018-05-17 23:40 (X/X)}",
"2018-03-26T11:11",
["11:40 Thursday 17 May 2018"],
],
[
"Time[]{2017-01-12 20:45 (X/X)}",
"2017-01-03T07:56",
["20:45 Donnerstag 12 Januar"],
],
[
"Time[]{2018-02-27 00:15 (X/X)}",
"2018-02-19T15:04",
["00:15 Tuesday 27 February 2018"],
],
[
"Time[]{2017-11-24 23:05 (X/X)}",
"2017-11-14T08:41",
["11:05 Friday 24 November 2017"],
],
["Time[]{2017-11-07 X:X (X/X)}", "2017-11-06T08:59", ["7th November 2017"]],
["Time[]{2018-03-31 X:X (X/X)}", "2018-03-11T21:48", ["am Freitag 31.3."]],
["Time[]{2017-12-12 X:X (X/X)}", "2017-12-06T12:11", ["am Dienstag 12.12"]],
["Time[]{2018-03-16 X:X (X/X)}", "2018-02-19T08:56", ["am Freitag 16.03"]],
["Time[]{2017-05-17 X:X (X/X)}", "2017-05-12T11:37", ["am Mittwoch 17.05"]],
["Time[]{2016-09-14 X:X (X/X)}", "2016-09-02T05:48", ["am Mittwoch 14.09."]],
["Time[]{2017-06-05 X:X (X/X)}", "2017-05-27T08:01", ["am Montag 05.06."]],
["Time[]{2018-03-23 X:X (X/X)}", "2018-03-14T10:42", ["on Friday 23/03"]],
["Time[]{2018-01-22 X:X (X/X)}", "2018-01-15T13:05", ["on Monday 22nd January"]],
["Time[]{2016-03-31 X:X (X/X)}", "2016-03-09T15:20", ["am Donnerstag 31.03."]],
[
"Time[]{2017-09-14 19:05 (X/X)}",
"2017-09-11T05:57",
["am Donnerstag, 14.09.17 07:05"],
],
["Time[]{2017-05-18 X:X (X/X)}", "2017-04-22T19:02", ["am Donnerstag den 18.05"]],
["Time[]{2016-03-17 X:X (X/X)}", "2016-03-11T09:15", ["am 17. M\u00e4rz 2016"]],
[
"Interval[]{2016-03-16 16:45 (X/X) - None}",
"2016-02-25T12:48",
["am 16.3.16 fr\u00fchestens 16:45 Uhr"],
],
["Time[]{2017-09-21 X:X (X/X)}", "2017-09-12T10:23", ["am 21.09"]],
[
"Time[]{2017-03-07 12:00 (X/X)}",
"2017-02-08T08:08",
["am 07.03.17 Mittag 12 Uhr"],
],
# [
# "Time[]{2017-12-06 X:X (X/lateafternoon)}",
# "2017-11-23T07:22",
# ["06.12.2017 Sp\u00e4tnachmittag"],
# ],
[
"Interval[]{2017-06-12 18:00 (X/X) - 2017-06-12 19:05 (X/X)}",
"2017-06-08T11:07",
["am 12.06.2017 18:00 - 19:05"],
],
[
"Time[]{2016-11-09 X:X (X/lateevening)}",
"2016-11-07T08:10",
["am 09.11.2016 sp\u00e4t Abends"],
],
[
"Interval[]{2018-03-09 17:00 (X/X) - None}",
"2018-02-15T14:47",
["am 09.03.2018 fr\u00fchstens 17 Uhr"],
],
[
"Time[]{2017-09-14 X:X (X/earlymorning)}",
"2017-09-05T10:10",
["am 14.09.2017 fr\u00fch morgens"],
],
[
"Interval[]{2017-05-16 X:X (X/X) - 2017-05-18 X:X (X/X)}",
"2017-05-12T11:16",
["von Dienstag 16.05 bis Donnerstag 18.05"],
],
[
"Interval[]{2018-02-05 X:X (X/X) - 2018-02-08 X:X (X/X)}",
"2018-02-03T09:20",
["von Montag 05.02 bis Donnerstag 08.02"],
],
[
"Interval[]{2018-02-24 X:X (X/X) - 2018-02-26 X:X (X/X)}",
"2018-02-07T16:28",
["from 24.02.2018 to 26.02.2018"],
],
["Time[]{2017-06-23 X:X (X/X)}", "2017-06-22T07:20", ["morgen 23.06"]],
[
"Interval[]{2018-03-15 X:X (X/X) - 2018-03-16 X:X (X/X)}",
"2018-03-05T12:51",
["15.3-16.3"],
],
[
"Interval[]{2017-11-28 13:13 (X/X) - 2017-11-28 13:44 (X/X)}",
"2017-11-27T15:14",
["morgen, 28.11.2017 um 13:13 - 13:44 Uhr"],
],
["Time[]{1993-07-02 X:X (X/X)}", "2017-11-27T15:14", ["2 jul 93"]],
["Time[]{2022-07-02 X:X (X/X)}", "2017-11-27T15:14", ["2 jul 22"]],
# [
# "Interval[]{2018-06-07 X:X (X/evening) - 2018-06-07 X:X (X/night)}",
# "2018-05-08T16:32",
# ["at 7.6 evening/night"],
# ],
]
================================================
FILE: ctparse/time/corpus.py
================================================
corpus = [
# ruleYear
("Time[]{2019-X-X X:X (X/X)}", "2018-03-07T12:43", ["2019"]),
# ruleToday
(
"Time[]{2018-03-07 X:X (X/X)}",
"2018-03-07T12:43",
["heute", "zu dieser zeit", "today"],
),
# ruleNow
(
"Time[]{2018-03-07 12:43 (X/X)}",
"2018-03-07T12:43",
["jetzt", "genau jetzt", "gerade eben", "rightnow", "just now"],
),
# ruleTomorrow
("Time[]{2019-01-01 X:X (X/X)}", "2018-12-31T12:43", ["morgen", "tomorrow", "tom", "tmrw"]),
# ruleAfterTomorrow
("Time[]{2019-01-02 X:X (X/X)}", "2018-12-31T12:43", ["übermorgen"]),
# ruleTomorrow + time
(
"Time[]{2019-01-01 19:25 (X/X)}",
"2018-12-31T12:43",
["morgen 19:25", "tomorrow 7:25 pm"],
),
# ruleYesterday
# test on a leap-year
("Time[]{2020-02-29 X:X (X/X)}", "2020-03-01T12:43", ["gestern", "yesterday"]),
# ruleBeforeYesterday
# test on a leap-year
("Time[]{2020-02-28 X:X (X/X)}", "2020-03-01T12:43", ["vorgestern"]),
# ruleEOM
(
"Time[]{2018-03-31 X:X (X/X)}",
"2018-03-07T12:43",
["ende des Monats", "eom", "end of the month"],
),
# ruleEOY
(
"Time[]{2018-12-31 X:X (X/X)}",
"2018-03-07T12:43",
["ende des Jahres", "eoy", "end of the year"],
),
# ruleNamedDOW
("Time[]{2018-03-12 X:X (X/X)}", "2018-03-07T12:43", ["Montag", "mon", "monday"]),
(
"Time[]{2018-03-13 X:X (X/X)}",
"2018-03-07T12:43",
["Dienstag", "tuesday", "tue"],
),
# ruleNamedDOW + POD
# ("Time[]{2018-03-12 X:X (X/morning)}", "2018-03-07T12:43", ["Montagmorgen"]),
# ("Time[]{2018-03-14 X:X (X/forenoon)}", "2018-03-07T12:43", ["Mittwochvormittag"]),
# ("Time[]{2018-03-10 X:X (X/morning)}", "2018-03-07T12:43", ["Samstagfrüh"]),
# (
# "Time[]{2018-03-11 X:X (X/night)}",
# "2018-03-07T12:43",
# ["sunday night", "Sonntagnacht"],
# ),
# ruleNamedMonth
("Time[]{2023-01-01 X:X (X/X)}", "2022-11-28T12:43", ["1st January", "1st jan."]),
("Time[]{2023-04-15 X:X (X/X)}", "2022-11-28T12:43", ["15 April", "15 apr."]),
("Time[]{X-07-X X:X (X/X)}", "2022-11-28T12:43", ["Juli", "July", "Jul"]),
(
"Time[]{2022-12-24 X:X (X/X)}",
"2022-11-28T12:43",
["24 Dezember", "December 24", "24 Dec.", "24 Dez."],
),
# ruleAtDOW
("Time[]{2018-03-13 X:X (X/X)}", "2018-03-07T12:43", ["am Dienstag", "on Tue"]),
(
"Time[]{2018-03-14 X:X (X/X)}",
"2018-03-07T12:43",
["this Wednesday", "diesen Mittwoch"],
),
# ruleNextDOW
(
"Time[]{2018-03-16 X:X (X/X)}",
"2018-03-07T12:43",
[
"am nächsten Freitag",
"next Friday",
"nächste Woche Freitag",
"Friday next week",
"on the following Friday",
],
),
# ruleDOYYear, ruleDDMM, ruleDDMMYYYY
(
"Time[]{2018-05-08 X:X (X/X)}",
"2018-03-07T12:43",
[
"8.5.2018",
"8. Mai 2018",
"8. Mai 18",
"8 May 2018",
"8 May",
"May 8",
"8/5",
"8.5.",
"am 8. Mai 2018",
"diesen 8. Mai 18",
"den 8.5.",
"8th May",
"8th of May",
"May 8th",
"at 8th May",
"on 8th of May",
"this May 8th",
"may 8",
],
),
(
"Time[]{2022-12-24 X:X (X/X)}",
"2022-11-29T12:43",
[
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"12/24",
"24/12",
"24/12",
"24/12",
],
),
# ruleDOWDOM
(
"Time[]{2022-11-29 X:X (X/X)}",
"2022-11-28T12:43",
["Tuesday 29th", "Tuesday the 29th", "Dienstag der 29."],
),
(
"Time[]{2018-06-02 X:X (X/X)}",
"2018-03-07T12:43",
["Saturday 2nd", "Jun 2nd", "am 2ten Juni"],
),
# ruleDOWDate, ruleDateDOW
(
"Time[]{2018-05-08 X:X (X/X)}",
"2018-03-07T12:43",
["Tuesday 8.5", "8.5 Tuesday"],
),
# (
# "Time[]{2018-05-08 X:X (X/morning)}",
# "2018-03-07T12:43",
# ["Dienstagmorgen 8.5.", "8.5. Dienstagmorgen"],
# ),
# rulePOD, ruleLatentPOD
# (
# "Time[]{2018-03-08 X:X (X/morning)}",
# "2018-03-07T12:43",
# ["morgens", "früh", "in der früh", "early", "morning"],
# ),
# (
# "Time[]{2018-03-08 X:X (X/earlymorning)}",
# "2018-03-07T12:43",
# ["früh morgens", "sehr früh", "early morning"],
# ),
# (
# "Time[]{2018-03-08 X:X (X/forenoon)}",
# "2018-03-07T12:43",
# ["vormittags", "forenoon"],
# ),
# before noon case
# (
# "Interval[]{None - 2018-03-08 X:X (X/noon)}",
# "2018-03-07T12:43",
# ["vor mittags", "before noon"],
# ),
# (
# "Time[]{2018-03-08 X:X (X/afternoon)}",
# "2018-03-07T12:43",
# ["nachmittag", "afternoon"],
# ),
# # past noon case
# (
# "Interval[]{2018-03-08 X:X (X/noon) - None}",
# "2018-03-07T12:43",
# ["nach mittag", "after noon"],
# ),
# ("Time[]{2018-03-08 X:X (X/noon)}", "2018-03-07T12:43", ["mittags", "noon"]),
# (
# "Time[]{2018-03-07 X:X (X/evening)}",
# "2018-03-07T12:43",
# ["abends", "late", "spät"],
# ),
# (
# "Time[]{2018-03-07 X:X (X/lateevening)}",
# "2018-03-07T12:43",
# ["später abend", "very late", "late evening"],
# ),
# (
# "Time[]{2018-03-08 X:X (X/veryearlyafternoon)}",
# "2018-03-07T12:43",
# ["sehr früher nachmittag", "very early afternoon"],
# ),
# (
# "Time[]{2018-03-07 X:X (X/night)}",
# "2018-03-07T12:43",
# ["heute nacht", "this night", "nachts"],
# ),
# # First/Last
# (
# "Time[]{2018-03-08 X:X (X/first)}",
# "2018-03-07T12:43",
# [
# "tomorrow first",
# "morgen erster",
# "morgen so früh wie möglich",
# "tomorrow earliest possible",
# ],
# ),
# (
# "Time[]{2018-03-08 X:X (X/last)}",
# "2018-03-07T12:43",
# [
# "tomorrow last",
# "morgen letzter",
# "tomorrow as late as possible",
# "morgen spätest möglicher",
# ],
# ),
# (
# "Time[]{2018-03-09 X:X (X/first)}",
# "2018-03-07T12:43",
# ["Friday first", "Freitag erster"],
# ),
# (
# "Time[]{2018-03-13 X:X (X/last)}",
# "2018-03-07T12:43",
# ["Tuesday last", "Dienstag letzter"],
# ),
# # Date + POD
# (
# "Time[]{2017-01-25 X:X (X/evening)}",
# "2018-03-07T12:43",
# [
# "25.01.2017 abends",
# "evening of January 25th 2017",
# "25.01.2017 late",
# "25.01.2017 spät",
# "25.01.2017 (spät)",
# ],
# ),
# (
# "Time[]{2017-01-25 X:X (X/lateafternoon)}",
# "2018-03-07T12:43",
# [
# "25.01.2017 spät nachmittags",
# "am 25. Januar 2017 am späten Nachmittag",
# "am 25. Januar 2017 am späten Nachmittag",
# "am 25. Januar 2017 am späten Nachmittag",
# "late afternoon of January 25th 2017",
# ],
# ),
# (
# "Time[]{2020-01-25 X:X (X/evening)}",
# "2018-03-07T12:43",
# [
# "25.01.2020 abends",
# "25.01.2020 late",
# "25.01.2020 spät",
# "25. Januar 2020 abends",
# "abends 25.01.2020",
# "evening of January 25th 2020",
# ],
# ),
# (
# "Time[]{2018-03-25 X:X (X/evening)}",
# "2018-03-07T12:43",
# ["evening of the 25th", "am 25. abends", "abends am 25."],
# ),
# # ruleTODPOD
# (
# "Time[]{X-X-X 16:30 (X/X)}",
# "2018-03-07T12:43",
# ["um 4:30 nachmittags", "at 4:30 in the afternoon"],
# ),
# rulePODTOD
# (
# "Time[]{X-X-X 20:00 (X/X)}", # next day since moning is already over
# "2018-03-07T12:43",
# ["morgens um 8", "late morning at 8"],
# ),
(
"Time[]{X-X-X 16:30 (X/X)}",
"2018-03-07T12:43",
["nachmittags um 16:30", "afternoon at 16:30", "16:30"],
),
# ruleDateTOD
(
"Time[]{2018-08-05 20:00 (X/X)}",
"2018-03-07T12:43",
[
"5. August u
gitextract_m6r5n4y6/ ├── .codecov.yml ├── .editorconfig ├── .github/ │ └── ISSUE_TEMPLATE.md ├── .gitignore ├── .pyup.yml ├── .travis.yml ├── AUTHORS.rst ├── CONTRIBUTING.rst ├── HISTORY.rst ├── LICENSE ├── MANIFEST.in ├── Makefile ├── README.rst ├── ctparse/ │ ├── __init__.py │ ├── corpus.py │ ├── count_vectorizer.py │ ├── ctparse.py │ ├── loader.py │ ├── models/ │ │ ├── __init__.py │ │ ├── dummy.py │ │ └── model.pbz │ ├── nb_estimator.py │ ├── nb_scorer.py │ ├── partial_parse.py │ ├── pipeline.py │ ├── py.typed │ ├── rule.py │ ├── scorer.py │ ├── time/ │ │ ├── __init__.py │ │ ├── auto_corpus.py │ │ ├── corpus.py │ │ ├── postprocess_latent.py │ │ └── rules.py │ ├── timers.py │ └── types.py ├── datasets/ │ ├── README.rst │ └── timeparse_corpus.json ├── docs/ │ ├── Makefile │ ├── authors.rst │ ├── conf.py │ ├── contributing.rst │ ├── ctparse.rst │ ├── ctparse.time.rst │ ├── dataset.rst │ ├── history.rst │ ├── index.rst │ ├── installation.rst │ ├── make.bat │ ├── modules.rst │ ├── readme.rst │ └── usage.rst ├── mypy.ini ├── requirements.txt ├── requirements_dev.txt ├── scripts/ │ └── train_default_model.py ├── setup.cfg ├── setup.py ├── tests/ │ ├── __init__.py │ ├── test_corpus.py │ ├── test_count_vectorizer.py │ ├── test_ctparse.py │ ├── test_partialparse.py │ ├── test_regressions.py │ ├── test_rule.py │ ├── test_scorer.py │ ├── test_time_rules.py │ ├── test_timers.py │ └── test_types.py └── tox.ini
SYMBOL INDEX (315 symbols across 26 files)
FILE: ctparse/corpus.py
function make_partial_rule_dataset (line 23) | def make_partial_rule_dataset(
function _progress_bar (line 94) | def _progress_bar(
function load_timeparse_corpus (line 104) | def load_timeparse_corpus(fname: str) -> Sequence[TimeParseEntry]:
function parse_nb_string (line 123) | def parse_nb_string(gold_parse: str) -> Union[Time, Interval, Duration]:
function run_corpus (line 138) | def run_corpus(
FILE: ctparse/count_vectorizer.py
class CountVectorizer (line 5) | class CountVectorizer:
method __init__ (line 6) | def __init__(self, ngram_range: Tuple[int, int]):
method _create_ngrams (line 23) | def _create_ngrams(
method _get_feature_counts (line 63) | def _get_feature_counts(
method _build_vocabulary (line 95) | def _build_vocabulary(count_matrix: Sequence[Dict[str, int]]) -> Dict[...
method _create_feature_matrix (line 115) | def _create_feature_matrix(
method fit (line 150) | def fit(self, documents: Sequence[Sequence[str]]) -> "CountVectorizer":
method fit_transform (line 166) | def fit_transform(
method transform (line 186) | def transform(self, documents: Sequence[Sequence[str]]) -> Sequence[Di...
FILE: ctparse/ctparse.py
class CTParse (line 36) | class CTParse:
method __init__ (line 37) | def __init__(
method __repr__ (line 59) | def __repr__(self) -> str:
method __str__ (line 63) | def __str__(self) -> str:
function ctparse (line 68) | def ctparse(
function ctparse_gen (line 136) | def ctparse_gen(
function _ctparse (line 226) | def _ctparse(
function _get_labels (line 390) | def _get_labels(txt: str) -> str:
function _preprocess_string (line 396) | def _preprocess_string(txt: str) -> str:
function _match_rule (line 402) | def _match_rule(
function _match_regex (line 425) | def _match_regex(txt: str, regexes: Dict[int, regex.Regex]) -> List[Rege...
function _regex_stack (line 442) | def _regex_stack(
FILE: ctparse/loader.py
function load_default_scorer (line 16) | def load_default_scorer() -> Scorer:
FILE: ctparse/models/dummy.py
function model_package_init (line 1) | def model_package_init():
FILE: ctparse/nb_estimator.py
function _log_sum_exp (line 5) | def _log_sum_exp(x: Sequence[float]) -> float:
class MultinomialNaiveBayes (line 11) | class MultinomialNaiveBayes:
method __init__ (line 17) | def __init__(self, alpha: float = 1.0):
method _construct_log_class_prior (line 31) | def _construct_log_class_prior(y: Sequence[int]) -> Tuple[float, float]:
method _construct_log_likelihood (line 41) | def _construct_log_likelihood(
method fit (line 75) | def fit(
method predict_log_probability (line 96) | def predict_log_probability(
FILE: ctparse/nb_scorer.py
class NaiveBayesScorer (line 16) | class NaiveBayesScorer(Scorer):
method __init__ (line 17) | def __init__(self, nb_model: CTParsePipeline) -> None:
method from_model_file (line 36) | def from_model_file(cls, fname: str) -> "NaiveBayesScorer":
method score (line 40) | def score(self, txt: str, ts: datetime, partial_parse: PartialParse) -...
method score_final (line 53) | def score_final(
function _feature_extractor (line 73) | def _feature_extractor(
function train_naive_bayes (line 79) | def train_naive_bayes(X: Sequence[Sequence[str]], y: Sequence[bool]) -> ...
function save_naive_bayes (line 90) | def save_naive_bayes(model: CTParsePipeline, fname: str) -> None:
FILE: ctparse/partial_parse.py
class PartialParse (line 24) | class PartialParse:
method __init__ (line 25) | def __init__(
method from_regex_matches (line 46) | def from_regex_matches(
method apply_rule (line 73) | def apply_rule(
method __lt__ (line 109) | def __lt__(self, other: "PartialParse") -> bool:
method __repr__ (line 122) | def __repr__(self) -> str:
method _filter_rules (line 127) | def _filter_rules(
function _seq_match (line 145) | def _seq_match(
FILE: ctparse/pipeline.py
class CTParsePipeline (line 7) | class CTParsePipeline:
method __init__ (line 8) | def __init__(self, transformer: CountVectorizer, estimator: Multinomia...
method fit (line 22) | def fit(self, X: Sequence[Sequence[str]], y: Sequence[int]) -> "CTPars...
method predict_log_proba (line 35) | def predict_log_proba(
FILE: ctparse/rule.py
function rule (line 57) | def rule(*patterns: Union[str, Predicate], **kwargs) -> Callable[[Any], ...
function regex_match (line 124) | def regex_match(r_id: int) -> Predicate:
function dimension (line 131) | def dimension(dim: Type[Artifact]) -> Predicate:
function predicate (line 138) | def predicate(pred: str) -> Predicate:
FILE: ctparse/scorer.py
class Scorer (line 14) | class Scorer(metaclass=ABCMeta):
method score (line 18) | def score(self, txt: str, ts: datetime, partial_parse: PartialParse) -...
method score_final (line 27) | def score_final(
class DummyScorer (line 39) | class DummyScorer(Scorer):
method score (line 42) | def score(self, txt: str, ts: datetime, partial_parse: PartialParse) -...
method score_final (line 45) | def score_final(
class RandomScorer (line 51) | class RandomScorer(Scorer):
method __init__ (line 52) | def __init__(self, rng: Optional[Random] = None) -> None:
method score (line 60) | def score(self, txt: str, ts: datetime, partial_parse: PartialParse) -...
method score_final (line 63) | def score_final(
FILE: ctparse/time/postprocess_latent.py
function apply_postprocessing_rules (line 8) | def apply_postprocessing_rules(ts: datetime, art: Artifact) -> Artifact:
function _latent_tod (line 34) | def _latent_tod(ts: datetime, tod: Time) -> Time:
function _latent_time_interval (line 47) | def _latent_time_interval(ts: datetime, ti: Interval) -> Interval:
FILE: ctparse/time/rules.py
function ruleAbsorbOnTime (line 14) | def ruleAbsorbOnTime(ts: datetime, pm_bias: bool, date_format: str, _: R...
function ruleAbsorbFromInterval (line 19) | def ruleAbsorbFromInterval(ts: datetime, pm_bias: bool, date_format: str...
function ruleNamedDOW (line 37) | def ruleNamedDOW(ts: datetime, pm_bias: bool, date_format: str, m: Regex...
function ruleNamedMonth (line 62) | def ruleNamedMonth(ts: datetime, pm_bias: bool, date_format: str, m: Reg...
function ruleNamedHour (line 89) | def ruleNamedHour(ts: datetime, pm_bias: bool, date_format: str, m: Rege...
function ruleMidnight (line 98) | def ruleMidnight(ts: datetime, pm_bias: bool, date_format: str, _: Regex...
function _pod_from_match (line 102) | def _pod_from_match(pod: str, m: RegexMatch) -> str:
function ruleEarlyLatePOD (line 119) | def ruleEarlyLatePOD(ts: datetime, pm_bias: bool, date_format: str, m: R...
function rulePOD (line 152) | def rulePOD(ts: datetime, pm_bias: bool, date_format: str, m: RegexMatch...
function ruleDOM1 (line 160) | def ruleDOM1(ts: datetime, pm_bias: bool, date_format: str, m: RegexMatc...
function ruleMonthOrdinal (line 166) | def ruleMonthOrdinal(ts: datetime, pm_bias: bool, date_format: str, m: R...
function ruleDOM2 (line 173) | def ruleDOM2(ts: datetime, pm_bias: bool, date_format: str, m: RegexMatc...
function ruleYear (line 178) | def ruleYear(ts: datetime, pm_bias: bool, date_format: str, m: RegexMatc...
function ruleToday (line 208) | def ruleToday(ts: datetime, pm_bias: bool, date_format: str, _: RegexMat...
function ruleNow (line 216) | def ruleNow(ts: datetime, pm_bias: bool, date_format: str, _: RegexMatch...
function ruleTomorrow (line 223) | def ruleTomorrow(ts: datetime, pm_bias: bool, date_format: str, _: Regex...
function ruleAfterTomorrow (line 229) | def ruleAfterTomorrow(ts: datetime, pm_bias: bool, date_format: str, _: ...
function ruleYesterday (line 235) | def ruleYesterday(ts: datetime, pm_bias: bool, date_format: str, _: Rege...
function ruleBeforeYesterday (line 241) | def ruleBeforeYesterday(ts: datetime, pm_bias: bool, date_format: str, _...
function ruleEOM (line 247) | def ruleEOM(ts: datetime, pm_bias: bool, date_format: str, _: RegexMatch...
function ruleEOY (line 256) | def ruleEOY(ts: datetime, pm_bias: bool, date_format: str, _: RegexMatch...
function ruleDOMMonth (line 262) | def ruleDOMMonth(ts: datetime, pm_bias: bool, date_format: str, dom: Tim...
function ruleDOMMonth2 (line 267) | def ruleDOMMonth2(ts: datetime, pm_bias: bool, date_format: str, dom: Ti...
function ruleMonthDOM (line 272) | def ruleMonthDOM(ts: datetime, pm_bias: bool, date_format: str, m: Time,...
function ruleAtDOW (line 277) | def ruleAtDOW(ts: datetime, pm_bias: bool, date_format: str, _: RegexMat...
function ruleNextDOW (line 289) | def ruleNextDOW(ts: datetime, pm_bias: bool, date_format: str, _: RegexM...
function ruleDOWNextWeek (line 295) | def ruleDOWNextWeek(ts: datetime, pm_bias: bool, date_format: str, dow: ...
function ruleDOYYear (line 301) | def ruleDOYYear(ts: datetime, pm_bias: bool, date_format: str, doy: Time...
function ruleDOWPOD (line 306) | def ruleDOWPOD(ts: datetime, pm_bias: bool, date_format: str, dow: Time,...
function ruleDOWDOM (line 311) | def ruleDOWDOM(ts: datetime, pm_bias: bool, date_format: str, dow: Time,...
function ruleDOWDate (line 319) | def ruleDOWDate(ts: datetime, pm_bias: bool, date_format: str, dow: Time...
function ruleDateDOW (line 325) | def ruleDateDOW(ts: datetime, pm_bias: bool, date_format: str, date: Tim...
function ruleLatentDOM (line 333) | def ruleLatentDOM(ts: datetime,pm_bias: bool, date_format: str, dom: Tim...
function ruleLatentDOW (line 341) | def ruleLatentDOW(ts: datetime, pm_bias: bool, date_format: str, dow: Ti...
function ruleLatentDOY (line 349) | def ruleLatentDOY(ts: datetime, pm_bias: bool, date_format: str, doy: Ti...
function ruleLatentPOD (line 357) | def ruleLatentPOD(ts: datetime, pm_bias: bool, date_format: str, pod: Ti...
function ruleDDMM (line 376) | def ruleDDMM(ts: datetime, pm_bias: bool, date_format: str, m: RegexMatc...
function ruleMMDD (line 398) | def ruleMMDD(ts: datetime, pm_bias: bool, date_format: str, m: RegexMatc...
function ruleDDMMYYYY (line 414) | def ruleDDMMYYYY(ts: datetime, pm_bias: bool, date_format: str, m: Regex...
function ruleMMDDYYYY (line 439) | def ruleMMDDYYYY(ts: datetime, pm_bias: bool, date_format: str, m: Regex...
function _is_valid_military_time (line 460) | def _is_valid_military_time(ts: datetime, pm_bias: bool, date_format: st...
function _maybe_apply_am_pm (line 484) | def _maybe_apply_am_pm(t: Time, pm_bias: bool, date_format: str, ampm_ma...
function ruleHHMMmilitary (line 519) | def ruleHHMMmilitary(ts: datetime, pm_bias: bool, date_format: str, m: R...
function ruleHHMM (line 535) | def ruleHHMM(ts: datetime, pm_bias: bool, date_format: str, m: RegexMatc...
function ruleHHOClock (line 544) | def ruleHHOClock(ts: datetime, pm_bias: bool, date_format: str, m: Regex...
function ruleQuarterBeforeHH (line 549) | def ruleQuarterBeforeHH(ts: datetime, pm_bias: bool, date_format:str, _:...
function ruleQuarterAfterHH (line 560) | def ruleQuarterAfterHH(ts: datetime, pm_bias: bool, date_format: str, _:...
function ruleHalfBeforeHH (line 567) | def ruleHalfBeforeHH(ts: datetime, pm_bias: bool, date_format: str, _: R...
function ruleHalfAfterHH (line 577) | def ruleHalfAfterHH(ts: datetime, pm_bias: bool, date_format: str, _: Re...
function ruleTODPOD (line 584) | def ruleTODPOD(ts: datetime, pm_bias: bool, date_format: str, tod: Time,...
function rulePODTOD (line 605) | def rulePODTOD(ts: datetime, pm_bias: bool, date_format: str, pod: Time,...
function ruleDateTOD (line 610) | def ruleDateTOD(ts: datetime, pm_bias: bool, date_format: str, date: Tim...
function ruleTODDate (line 617) | def ruleTODDate(ts: datetime, pm_bias: bool, date_format: str, tod: Time...
function ruleDatePOD (line 624) | def ruleDatePOD(ts: datetime, pm_bias: bool, date_format: str, d: Time, ...
function rulePODDate (line 629) | def rulePODDate(ts: datetime, pm_bias: bool, date_format: str, pod: Time...
function ruleBeforeTime (line 637) | def ruleBeforeTime(ts: datetime, pm_bias: bool, date_format: str, r: Reg...
function ruleAfterTime (line 649) | def ruleAfterTime(ts: datetime, pm_bias: bool, date_format: str, r: Rege...
function ruleDateDate (line 657) | def ruleDateDate(ts: datetime, pm_bias: bool, date_format: str, d1: Time...
function ruleDOMDate (line 668) | def ruleDOMDate(ts: datetime, pm_bias: bool, date_format: str, d1: Time,...
function ruleDateDOM (line 675) | def ruleDateDOM(ts: datetime, pm_bias: bool, date_format: str, d1: Time,...
function ruleDOYDate (line 682) | def ruleDOYDate(ts: datetime, pm_bias: bool, date_format: str, d1: Time,...
function ruleDateTimeDateTime (line 691) | def ruleDateTimeDateTime(
function ruleTODTOD (line 719) | def ruleTODTOD(ts: datetime, pm_bias: bool, date_format: str, t1: Time, ...
function rulePODPOD (line 740) | def rulePODPOD(ts: datetime, pm_bias: bool, date_format: str, t1: Time, ...
function ruleDateInterval (line 745) | def ruleDateInterval(ts: datetime, pm_bias: bool, date_format: str, d: T...
function ruleIntervalDate (line 784) | def ruleIntervalDate(ts: datetime, pm_bias: bool, date_format: str, i: I...
function rulePODInterval (line 823) | def rulePODInterval(ts: datetime, pm_bias: bool, date_format: str, p: Ti...
function ruleDigitDuration (line 921) | def ruleDigitDuration(ts: datetime, pm_bias: bool, date_format: str, m: ...
function ruleNamedNumberDuration (line 934) | def ruleNamedNumberDuration(ts: datetime, pm_bias: bool, date_format: st...
function ruleDurationHalf (line 953) | def ruleDurationHalf(ts: datetime, pm_bias: bool, date_format: str, m: R...
function ruleIntervalFromDuration (line 998) | def ruleIntervalFromDuration(
function _duration_to_relativedelta (line 1037) | def _duration_to_relativedelta(dur: Duration) -> relativedelta:
function ruleTimeDuration (line 1049) | def ruleTimeDuration(ts: datetime, pm_bias: bool, date_format: str, t: T...
function ruleDurationTime (line 1063) | def ruleDurationTime(ts: datetime, pm_bias: bool, date_format: str, d: D...
function ruleDurationInterval (line 1077) | def ruleDurationInterval(ts: datetime, pm_bias: bool, date_format: str, ...
function ruleIntervalDuration (line 1102) | def ruleIntervalDuration(ts: datetime, pm_bias: bool, date_format: str, ...
function ruleRecurringSingle (line 1187) | def ruleRecurringSingle(ts: datetime, pm_bias: bool, date_format: str, m...
function ruleRecurring (line 1199) | def ruleRecurring(ts: datetime, pm_bias: bool, date_format: str, m: Rege...
function ruleRecurringIntervals (line 1212) | def ruleRecurringIntervals(ts: datetime, pm_bias: bool, date_format: str...
function ruleDefinedRecurringIntervals (line 1227) | def ruleDefinedRecurringIntervals(ts: datetime, pm_bias: bool, date_form...
function ruleDefinedRecurringIntervals2 (line 1248) | def ruleDefinedRecurringIntervals2(ts: datetime, pm_bias: bool, date_for...
function ruleRecurringTime (line 1269) | def ruleRecurringTime(ts: datetime, pm_bias: bool, date_format: str, t: ...
function ruleRecurringTime2 (line 1289) | def ruleRecurringTime2(ts: datetime, pm_bias: bool, date_format: str, r:...
function ruleRecurringTimeInterval (line 1310) | def ruleRecurringTimeInterval(ts: datetime, pm_bias: bool, date_format: ...
function ruleRecurringTimeInterval2 (line 1335) | def ruleRecurringTimeInterval2(ts: datetime, pm_bias: bool, date_format:...
function ruleRecurringDOW (line 1360) | def ruleRecurringDOW(ts: datetime, pm_bias: bool, date_format: str, m: R...
function ruleRecurringDOY (line 1370) | def ruleRecurringDOY(ts: datetime, pm_bias: bool, date_format: str, m: R...
function ruleRecurringIntervalDOW (line 1380) | def ruleRecurringIntervalDOW(ts: datetime, pm_bias: bool, date_format: s...
function ruleRecurringDOWS (line 1395) | def ruleRecurringDOWS(ts: datetime, pm_bias: bool, date_format: str, m: ...
function ruleRecurringSimpleDOWDOW (line 1409) | def ruleRecurringSimpleDOWDOW(ts: datetime, pm_bias: bool, date_format: ...
function ruleRecurringDOWDOW (line 1415) | def ruleRecurringDOWDOW(ts: datetime, pm_bias: bool, date_format: str, m...
function ruleRecurringDOW2DOW (line 1431) | def ruleRecurringDOW2DOW(ts: datetime, pm_bias: bool, date_format: str, ...
function ruleRecurringWeekdays (line 1466) | def ruleRecurringWeekdays(ts: datetime, pm_bias: bool, date_format: str,...
function ruleDurationRecurring (line 1484) | def ruleDurationRecurring(ts: datetime, pm_bias: bool, date_format: str,...
function ruleNextFrequency (line 1496) | def ruleNextFrequency(ts: datetime, pm_bias: bool, date_format: str, m: ...
function ruleLastDOM (line 1518) | def ruleLastDOM(ts: datetime, pm_bias: bool, date_format: str, m: RegexM...
FILE: ctparse/timers.py
function timeout (line 14) | def timeout(timeout: Union[float, int]) -> Callable[[], None]:
function timeit (line 42) | def timeit(f: Callable[..., T]) -> Callable[..., Tuple[T, float]]:
class CTParseTimeoutError (line 69) | class CTParseTimeoutError(Exception):
FILE: ctparse/types.py
class Artifact (line 13) | class Artifact:
method __init__ (line 14) | def __init__(self) -> None:
method update_span (line 19) | def update_span(self: T, *args: "Artifact") -> T:
method __len__ (line 24) | def __len__(self) -> int:
method __bool__ (line 27) | def __bool__(self) -> bool:
method __str__ (line 30) | def __str__(self) -> str:
method __repr__ (line 33) | def __repr__(self) -> str:
method nb_str (line 38) | def nb_str(self) -> str:
method __eq__ (line 42) | def __eq__(self, other: Any) -> bool:
method __hash__ (line 48) | def __hash__(self) -> int:
method _hasOnly (line 51) | def _hasOnly(self, *args: str) -> bool:
method _hasAtLeast (line 61) | def _hasAtLeast(self, *args: str) -> bool:
class RegexMatch (line 69) | class RegexMatch(Artifact):
method __init__ (line 70) | def __init__(self, id: int, m: Regex) -> None:
method __str__ (line 80) | def __str__(self) -> str:
function _mk_pod_hours (line 238) | def _mk_pod_hours() -> Dict[str, Tuple[int, int]]:
class Time (line 268) | class Time(Artifact):
method __init__ (line 269) | def __init__(
method isDOY (line 297) | def isDOY(self) -> bool:
method isDOM (line 303) | def isDOM(self) -> bool:
method isDOW (line 309) | def isDOW(self) -> bool:
method isMonth (line 318) | def isMonth(self) -> bool:
method isPOD (line 322) | def isPOD(self) -> bool:
method isHour (line 329) | def isHour(self) -> bool:
method isTOD (line 334) | def isTOD(self) -> bool:
method isDate (line 339) | def isDate(self) -> bool:
method isDateTime (line 344) | def isDateTime(self) -> bool:
method isYear (line 351) | def isYear(self) -> bool:
method hasDate (line 356) | def hasDate(self) -> bool:
method hasDOY (line 361) | def hasDOY(self) -> bool:
method hasDOW (line 366) | def hasDOW(self) -> bool:
method hasTime (line 371) | def hasTime(self) -> bool:
method hasPeriod (line 376) | def hasPeriod(self) -> bool:
method hasPOD (line 381) | def hasPOD(self) -> bool:
method __str__ (line 385) | def __str__(self) -> str:
method from_str (line 397) | def from_str(cls: Type["Time"], text: str) -> "Time":
method start (line 418) | def start(self) -> "Time":
method end (line 433) | def end(self) -> "Time":
method dt (line 448) | def dt(self) -> datetime:
class Interval (line 459) | class Interval(Artifact):
method __init__ (line 460) | def __init__(
method isTimeInterval (line 469) | def isTimeInterval(self) -> bool:
method isDateInterval (line 476) | def isDateInterval(self) -> bool:
method __str__ (line 481) | def __str__(self) -> str:
method from_str (line 485) | def from_str(cls: Type["Interval"], text: str) -> "Interval":
method start (line 495) | def start(self) -> Optional[Time]:
method end (line 502) | def end(self) -> Optional[Time]:
class DurationUnit (line 510) | class DurationUnit(enum.Enum):
class Duration (line 520) | class Duration(Artifact):
method __init__ (line 521) | def __init__(self, value: int, unit: DurationUnit):
method __str__ (line 532) | def __str__(self) -> str:
method from_str (line 536) | def from_str(cls: Type["Duration"], text: str) -> "Duration":
method time (line 540) | def time(self, ts: datetime) -> Time:
class RecurringFrequency (line 560) | class RecurringFrequency(enum.Enum):
class Recurring (line 567) | class Recurring(Artifact):
method __init__ (line 568) | def __init__(
method __str__ (line 588) | def __str__(self) -> str:
method isRecurring (line 592) | def isRecurring(self) -> bool:
method isRecurringDOW (line 599) | def isRecurringDOW(self) -> bool:
method isRecurringTime (line 606) | def isRecurringTime(self) -> bool:
method to_rrule (line 612) | def to_rrule(self) -> rrule:
class RecurringArray (line 618) | class RecurringArray(Artifact):
method __init__ (line 619) | def __init__(self,
method __str__ (line 634) | def __str__(self) -> str:
method to_list (line 638) | def to_list(self) -> list:
FILE: scripts/train_default_model.py
function parse_args (line 14) | def parse_args():
function main (line 25) | def main():
FILE: tests/test_corpus.py
function test_run_corpus (line 34) | def test_run_corpus() -> None:
function test_run_corpus_failure (line 43) | def test_run_corpus_failure() -> None:
function test_make_partial_rule_dataset (line 49) | def test_make_partial_rule_dataset() -> None:
function test_parse_nb_string (line 66) | def test_parse_nb_string() -> None:
function test_load_timeparse_corpus (line 75) | def test_load_timeparse_corpus(tmp_path) -> None:
FILE: tests/test_count_vectorizer.py
function test_ngrams (line 15) | def test_ngrams(ngrams, doc, result):
function test_count_vectorizer_fit_and_transform (line 19) | def test_count_vectorizer_fit_and_transform():
function test_count_vectorizer_fit_transform (line 26) | def test_count_vectorizer_fit_transform():
function test_count_vectorizer_transform_no_fit (line 41) | def test_count_vectorizer_transform_no_fit():
FILE: tests/test_ctparse.py
function test_ctparse (line 6) | def test_ctparse():
function test_ctparse_timeout (line 27) | def test_ctparse_timeout():
function test_match_rule (line 34) | def test_match_rule():
function test_latent_time (line 42) | def test_latent_time():
function test_latent_time_interval (line 52) | def test_latent_time_interval():
FILE: tests/test_partialparse.py
function test_partial_parse (line 11) | def test_partial_parse() -> None:
function test_seq_match (line 37) | def test_seq_match() -> None:
function _identity (line 116) | def _identity(x: Any) -> bool:
FILE: tests/test_regressions.py
function test_military_time (line 6) | def test_military_time():
function test_parse_years_ahead (line 12) | def test_parse_years_ahead():
FILE: tests/test_rule.py
class TestClassA (line 7) | class TestClassA(Artifact):
class TestClassB (line 11) | class TestClassB(Artifact):
class TestRule (line 15) | class TestRule(TestCase):
method test_empty_regex_match_not_allowed (line 16) | def test_empty_regex_match_not_allowed(self):
method test_consecutive_regex_not_allowed (line 28) | def test_consecutive_regex_not_allowed(self):
method test_regex_match (line 32) | def test_regex_match(self):
method test_dimension (line 38) | def test_dimension(self):
method test_predicate (line 42) | def test_predicate(self):
FILE: tests/test_scorer.py
function test_dummy (line 15) | def test_dummy():
function test_random (line 23) | def test_random():
function test_nbscorer (line 37) | def test_nbscorer():
function test_naive_bayes_from_file (line 61) | def test_naive_bayes_from_file(tmp_path):
function test_save_naive_bayes (line 72) | def test_save_naive_bayes(tmp_path):
FILE: tests/test_time_rules.py
class TestRules (line 14) | class TestRules(TestCase):
method test_ruleDateDate (line 15) | def test_ruleDateDate(self):
method test_ruleDOMDate (line 36) | def test_ruleDOMDate(self):
method test_ruleDateTimeDateTime (line 49) | def test_ruleDateTimeDateTime(self):
method test_ruleDOYDate (line 78) | def test_ruleDOYDate(self):
method test_ruleQuarterBeforeHH (line 87) | def test_ruleQuarterBeforeHH(self):
method test_ruleQuarterAferHH (line 91) | def test_ruleQuarterAferHH(self):
FILE: tests/test_timers.py
class TimersTest (line 6) | class TimersTest(TestCase):
method test_timeout (line 7) | def test_timeout(self):
method test_timeit (line 15) | def test_timeit(self):
FILE: tests/test_types.py
class TestArtifact (line 7) | class TestArtifact(TestCase):
method test_init (line 8) | def test_init(self):
method test_eq (line 15) | def test_eq(self):
method test_update_span (line 32) | def test_update_span(self):
method test_repr (line 43) | def test_repr(self):
method test_nb_str (line 47) | def test_nb_str(self):
class TestRegexMatch (line 52) | class TestRegexMatch(TestCase):
method test_init (line 53) | def test_init(self):
class TestTime (line 64) | class TestTime(TestCase):
method test_init (line 65) | def test_init(self):
method test_isDOY (line 68) | def test_isDOY(self):
method test_isDOM (line 72) | def test_isDOM(self):
method test_isHour (line 76) | def test_isHour(self):
method test_isDOW (line 81) | def test_isDOW(self):
method test_isMonth (line 85) | def test_isMonth(self):
method test_isPOD (line 90) | def test_isPOD(self):
method test_isTOD (line 95) | def test_isTOD(self):
method test_isDate (line 101) | def test_isDate(self):
method test_isDateTime (line 108) | def test_isDateTime(self):
method test_isYear (line 112) | def test_isYear(self):
method test_hasDate (line 116) | def test_hasDate(self):
method test_hasTime (line 123) | def test_hasTime(self):
method test_hasPOD (line 128) | def test_hasPOD(self):
method test_repr (line 132) | def test_repr(self):
method test_from_str (line 136) | def test_from_str(self):
method test_start (line 159) | def test_start(self):
method test_end (line 171) | def test_end(self):
method test_dt (line 183) | def test_dt(self):
class TestInterval (line 196) | class TestInterval(TestCase):
method test_init (line 197) | def test_init(self):
method test_isTimeInterval (line 200) | def test_isTimeInterval(self):
method test_repr (line 203) | def test_repr(self):
method test_from_str (line 209) | def test_from_str(self):
method test_start (line 231) | def test_start(self):
method test_end (line 241) | def test_end(self):
Condensed preview — 69 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (707K chars).
[
{
"path": ".codecov.yml",
"chars": 13,
"preview": "comment: off\n"
},
{
"path": ".editorconfig",
"chars": 292,
"preview": "# http://editorconfig.org\n\nroot = true\n\n[*]\nindent_style = space\nindent_size = 4\ntrim_trailing_whitespace = true\ninsert_"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 369,
"preview": "* ctparse - Parse natural language time expressions in pytho version:\n* Python version:\n* Operating System:\n\n### Descrip"
},
{
"path": ".gitignore",
"chars": 1227,
"preview": "# Byte-compiled / optimized / DLL files\n__pycache__/\n*.py[cod]\n*$py.class\n\n# C extensions\n*.so\n\n# Distribution / packagi"
},
{
"path": ".pyup.yml",
"chars": 123,
"preview": "# autogenerated pyup.io config file \n# see https://pyup.io/docs/configuration/ for all available options\n\nupdate: insecu"
},
{
"path": ".travis.yml",
"chars": 157,
"preview": "language: python\nsudo: required\ndist: xenial\npython:\n - 3.8\n - 3.7\n - 3.6\ninstall: pip install -U tox-travis codecov\n"
},
{
"path": "AUTHORS.rst",
"chars": 184,
"preview": "=======\nCredits\n=======\n\nDevelopment Lead\n----------------\n\n* Sebastian Mika <sebastian.mika@comtravo.com>\n\nContributors"
},
{
"path": "CONTRIBUTING.rst",
"chars": 11550,
"preview": "============\nContributing\n============\n\nContributions are welcome, and they are greatly appreciated! Every little bit\nhe"
},
{
"path": "HISTORY.rst",
"chars": 2417,
"preview": "=======\nHistory\n=======\n\n\n0.3.0 (2021-02-01)\n------------------\n\n* Removed latent rules regarding times (latent rules re"
},
{
"path": "LICENSE",
"chars": 1083,
"preview": "MIT License\n\nCopyright (c) 2018, Sebastian Mika, Comtravo\n\nPermission is hereby granted, free of charge, to any person o"
},
{
"path": "MANIFEST.in",
"chars": 287,
"preview": "include AUTHORS.rst\ninclude CONTRIBUTING.rst\ninclude HISTORY.rst\ninclude LICENSE\ninclude README.rst\ninclude requirements"
},
{
"path": "Makefile",
"chars": 2397,
"preview": ".PHONY: clean clean-test clean-pyc clean-build docs help\n.DEFAULT_GOAL := help\n\ndefine BROWSER_PYSCRIPT\nimport os, webbr"
},
{
"path": "README.rst",
"chars": 10948,
"preview": "===========================================================\nquickadd\n==================================================="
},
{
"path": "ctparse/__init__.py",
"chars": 245,
"preview": "\"\"\"ctparse - parse time expressions in strings\n\n.. moduleauthor:: Comtravo\n\n\"\"\"\n__author__ = \"\"\"Sebastian Mika\"\"\"\n__emai"
},
{
"path": "ctparse/corpus.py",
"chars": 8473,
"preview": "import json\nimport logging\nfrom datetime import datetime\nfrom typing import Callable, Iterable, List, NamedTuple, Sequen"
},
{
"path": "ctparse/count_vectorizer.py",
"chars": 7331,
"preview": "from collections import defaultdict\nfrom typing import Dict, Sequence, Tuple, Optional\n\n\nclass CountVectorizer:\n def "
},
{
"path": "ctparse/ctparse.py",
"chars": 20321,
"preview": "from ctparse.time.postprocess_latent import apply_postprocessing_rules\nimport logging\nfrom datetime import datetime\nfrom"
},
{
"path": "ctparse/loader.py",
"chars": 1302,
"preview": "\"\"\"Utility to load default model in ctparse\"\"\"\n\nimport bz2\nimport logging\nimport os\nimport pickle\nfrom .scorer import Sc"
},
{
"path": "ctparse/models/__init__.py",
"chars": 38,
"preview": "from .dummy import model_package_init\n"
},
{
"path": "ctparse/models/dummy.py",
"chars": 44,
"preview": "def model_package_init():\n return 1 == 1\n"
},
{
"path": "ctparse/nb_estimator.py",
"chars": 4479,
"preview": "from typing import Sequence, Dict, Tuple, List\nfrom math import log, exp\n\n\ndef _log_sum_exp(x: Sequence[float]) -> float"
},
{
"path": "ctparse/nb_scorer.py",
"chars": 3593,
"preview": "\"\"\"This module cointains the implementation of the scorer based on naive bayes.\"\"\"\nimport bz2\nimport math\nimport pickle\n"
},
{
"path": "ctparse/partial_parse.py",
"chars": 7635,
"preview": "import logging\nfrom datetime import datetime\nfrom typing import (\n Callable,\n Optional,\n Sequence,\n Tuple,\n "
},
{
"path": "ctparse/pipeline.py",
"chars": 1856,
"preview": "from typing import Sequence, Tuple\n\nfrom .nb_estimator import MultinomialNaiveBayes\nfrom .count_vectorizer import CountV"
},
{
"path": "ctparse/py.typed",
"chars": 26,
"preview": "# Marker file for PEP 561."
},
{
"path": "ctparse/rule.py",
"chars": 4551,
"preview": "# flake8: noqa F405\nimport logging\n\nfrom datetime import datetime\nfrom typing import Any, Callable, Dict, List, Optional"
},
{
"path": "ctparse/scorer.py",
"chars": 2032,
"preview": "\"\"\"This module contains the Scorer abstraction that can be used to\nimplement scoring strategies for ctparse.\n\"\"\"\n\nfrom a"
},
{
"path": "ctparse/time/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "ctparse/time/auto_corpus.py",
"chars": 94235,
"preview": "corpus = [ # pragma: no cover\n [\n \"Time[]{2018-01-04 X:X (X/X)}\",\n \"2017-12-20T20:34\",\n [\n "
},
{
"path": "ctparse/time/corpus.py",
"chars": 24572,
"preview": "corpus = [\n # ruleYear\n (\"Time[]{2019-X-X X:X (X/X)}\", \"2018-03-07T12:43\", [\"2019\"]),\n # ruleToday\n (\n "
},
{
"path": "ctparse/time/postprocess_latent.py",
"chars": 2281,
"preview": "\"\"\"Those rules are applied as postprocessing steps after scoring has been already\ndone. Needed for backwards compatibili"
},
{
"path": "ctparse/time/rules.py",
"chars": 53407,
"preview": "from typing import Optional, Any, cast\nfrom datetime import datetime, timedelta\nfrom dateutil.relativedelta import relat"
},
{
"path": "ctparse/timers.py",
"chars": 1875,
"preview": "\"\"\"Utilities for tracking time spent in functions.\n\nAlthough this module is not part of the public API, it is used in va"
},
{
"path": "ctparse/types.py",
"chars": 20612,
"preview": "from datetime import datetime\nfrom typing import Any, Dict, Optional, Tuple, Type, TypeVar, List\nfrom dateutil.relatived"
},
{
"path": "datasets/README.rst",
"chars": 1813,
"preview": "==================\nTime Parse Dataset\n==================\n\nThe dataset included in ``datasets/timeparse_corpus.json`` con"
},
{
"path": "datasets/timeparse_corpus.json",
"chars": 305427,
"preview": "[\n {\n \"text\": \"Donnerstag, den 05.10. ca 6:55\",\n \"ref_time\": \"2017-09-25T16:06:55\",\n \"gold_parse\": \"Time[]{2017-10-05"
},
{
"path": "docs/Makefile",
"chars": 608,
"preview": "# Minimal makefile for Sphinx documentation\n#\n\n# You can set these variables from the command line.\nSPHINXOPTS =\nSPHI"
},
{
"path": "docs/authors.rst",
"chars": 28,
"preview": ".. include:: ../AUTHORS.rst\n"
},
{
"path": "docs/conf.py",
"chars": 5053,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n#\n# ctparse documentation build configuration file, created by\n# sphinx-qu"
},
{
"path": "docs/contributing.rst",
"chars": 33,
"preview": ".. include:: ../CONTRIBUTING.rst\n"
},
{
"path": "docs/ctparse.rst",
"chars": 1882,
"preview": "ctparse package\n===============\n\nSubpackages\n-----------\n\n.. toctree::\n\n ctparse.time\n\nSubmodules\n----------\n\nctparse."
},
{
"path": "docs/ctparse.time.rst",
"chars": 481,
"preview": "ctparse.time package\n====================\n\nSubmodules\n----------\n\nctparse.time.corpus module\n--------------------------\n"
},
{
"path": "docs/dataset.rst",
"chars": 35,
"preview": ".. include:: ../datasets/README.rst"
},
{
"path": "docs/history.rst",
"chars": 28,
"preview": ".. include:: ../HISTORY.rst\n"
},
{
"path": "docs/index.rst",
"chars": 316,
"preview": "Welcome to the ctparse documentation!\n=====================================\n\n.. toctree::\n :maxdepth: 2\n :caption: C"
},
{
"path": "docs/installation.rst",
"chars": 1267,
"preview": ".. highlight:: shell\n\n============\nInstallation\n============\n\n\nStable release\n--------------\n\nTo install ctparse - Parse"
},
{
"path": "docs/make.bat",
"chars": 769,
"preview": "@ECHO OFF\n\npushd %~dp0\n\nREM Command file for Sphinx documentation\n\nif \"%SPHINXBUILD%\" == \"\" (\n\tset SPHINXBUILD=python -m"
},
{
"path": "docs/modules.rst",
"chars": 58,
"preview": "ctparse\n=======\n\n.. toctree::\n :maxdepth: 4\n\n ctparse\n"
},
{
"path": "docs/readme.rst",
"chars": 27,
"preview": ".. include:: ../README.rst\n"
},
{
"path": "docs/usage.rst",
"chars": 360,
"preview": "=====\nUsage\n=====\n\nTo use ctparse simply import the main ``ctparse`` function::\n\n \n from datetime import datetime\n"
},
{
"path": "mypy.ini",
"chars": 841,
"preview": "[mypy]\n# Specify the target platform details in config, so your developers are\n# free to run mypy on Windows, Linux, or "
},
{
"path": "requirements.txt",
"chars": 2,
"preview": ".\n"
},
{
"path": "requirements_dev.txt",
"chars": 242,
"preview": "pip==20.1.1\nbumpversion==0.6.0\nwatchdog==0.10.2\nflake8==3.8.2\nflake8-bugbear==20.1.4\ntox==3.15.1\ncoverage==5.1\nsphinx==3"
},
{
"path": "scripts/train_default_model.py",
"chars": 1795,
"preview": "\"\"\"Train a default multinomial bayes classifier\"\"\"\nimport argparse\nimport logging\n\nfrom ctparse.corpus import load_timep"
},
{
"path": "setup.cfg",
"chars": 601,
"preview": "[bumpversion]\ncurrent_version = 0.3.01\ncommit = True\ntag = True\n\n[bumpversion:file:setup.py]\nsearch = version='{current_"
},
{
"path": "setup.py",
"chars": 1666,
"preview": "#!/usr/bin/env python\n# -*- coding: utf-8 -*-\n\n\"\"\"The setup script.\"\"\"\n\nfrom setuptools import setup, find_packages\n\nwit"
},
{
"path": "tests/__init__.py",
"chars": 0,
"preview": ""
},
{
"path": "tests/test_corpus.py",
"chars": 2050,
"preview": "from datetime import datetime\n\nimport pytest\n\nfrom ctparse.corpus import (\n TimeParseEntry,\n load_timeparse_corpus"
},
{
"path": "tests/test_count_vectorizer.py",
"chars": 1294,
"preview": "import pytest\nfrom ctparse.count_vectorizer import CountVectorizer\n\n\n@pytest.mark.parametrize(\n \"ngrams,doc,result\",\n"
},
{
"path": "tests/test_ctparse.py",
"chars": 1988,
"preview": "from datetime import datetime\nfrom ctparse.ctparse import ctparse, ctparse_gen, _match_rule\nfrom ctparse.types import In"
},
{
"path": "tests/test_partialparse.py",
"chars": 3622,
"preview": "import datetime\nfrom typing import Any, Callable\n\nimport pytest\nimport regex\n\nfrom ctparse.partial_parse import PartialP"
},
{
"path": "tests/test_regressions.py",
"chars": 482,
"preview": "\"\"\"This file contains regression tests for commonly parsed time expressions\"\"\"\nimport ctparse\nfrom datetime import datet"
},
{
"path": "tests/test_rule.py",
"chars": 1310,
"preview": "from unittest import TestCase\nimport regex\nfrom ctparse.types import RegexMatch, Artifact\nfrom ctparse.rule import dimen"
},
{
"path": "tests/test_scorer.py",
"chars": 2158,
"preview": "import datetime\nimport random\nimport bz2\nimport pickle\n\nfrom ctparse.nb_scorer import NaiveBayesScorer, train_naive_baye"
},
{
"path": "tests/test_time_rules.py",
"chars": 3489,
"preview": "from unittest import TestCase\n\nfrom ctparse.types import Time\nfrom ctparse.time.rules import (\n ruleDateDate,\n rul"
},
{
"path": "tests/test_timers.py",
"chars": 546,
"preview": "from ctparse.timers import timeout, CTParseTimeoutError, timeit\nfrom unittest import TestCase\nimport time\n\n\nclass Timers"
},
{
"path": "tests/test_types.py",
"chars": 8484,
"preview": "from unittest import TestCase\nimport regex\nfrom datetime import datetime\nfrom ctparse.types import Artifact, RegexMatch,"
},
{
"path": "tox.ini",
"chars": 307,
"preview": "[tox]\nenvlist = py36, py37, py38\n\n[travis]\npython =\n 3.8: py38\n 3.7: py37\n 3.6: py36\n\n[testenv]\nwhitelist_exter"
}
]
// ... and 1 more files (download for full content)
About this extraction
This page contains the full source code of the Acreom/quickadd GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 69 files (624.0 KB), approximately 247.9k tokens, and a symbol index with 315 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.