temporal-normalization-spacy 1.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (20) hide show
  1. temporal_normalization_spacy-1.0.0/LICENSE +21 -0
  2. temporal_normalization_spacy-1.0.0/MANIFEST.in +6 -0
  3. temporal_normalization_spacy-1.0.0/PKG-INFO +251 -0
  4. temporal_normalization_spacy-1.0.0/README.md +227 -0
  5. temporal_normalization_spacy-1.0.0/setup.cfg +4 -0
  6. temporal_normalization_spacy-1.0.0/setup.py +27 -0
  7. temporal_normalization_spacy-1.0.0/temporal_normalization/__init__.py +5 -0
  8. temporal_normalization_spacy-1.0.0/temporal_normalization/commons/__init__.py +3 -0
  9. temporal_normalization_spacy-1.0.0/temporal_normalization/commons/print_utils.py +98 -0
  10. temporal_normalization_spacy-1.0.0/temporal_normalization/commons/temporal_models.py +105 -0
  11. temporal_normalization_spacy-1.0.0/temporal_normalization/commons/temporal_types.py +10 -0
  12. temporal_normalization_spacy-1.0.0/temporal_normalization/index.py +88 -0
  13. temporal_normalization_spacy-1.0.0/temporal_normalization/libs/temporal-normalization-1.6.jar +0 -0
  14. temporal_normalization_spacy-1.0.0/temporal_normalization/process/__init__.py +1 -0
  15. temporal_normalization_spacy-1.0.0/temporal_normalization/process/java_process.py +87 -0
  16. temporal_normalization_spacy-1.0.0/temporal_normalization_spacy.egg-info/PKG-INFO +251 -0
  17. temporal_normalization_spacy-1.0.0/temporal_normalization_spacy.egg-info/SOURCES.txt +18 -0
  18. temporal_normalization_spacy-1.0.0/temporal_normalization_spacy.egg-info/dependency_links.txt +1 -0
  19. temporal_normalization_spacy-1.0.0/temporal_normalization_spacy.egg-info/requires.txt +3 -0
  20. temporal_normalization_spacy-1.0.0/temporal_normalization_spacy.egg-info/top_level.txt +1 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Ilie
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,6 @@
1
+ include README.md
2
+ include temporal_normalization/libs/temporal-normalization-1.6.jar
3
+
4
+ recursive-include temporal_normalizer/commons *
5
+ recursive-include temporal_normalizer/libs *
6
+ recursive-include temporal_normalizer *
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.2
2
+ Name: temporal_normalization_spacy
3
+ Version: 1.0.0
4
+ Summary: A spaCy plugin for identifying and parsing historical data in Romanian texts
5
+ Home-page: https://github.com/iliedorobat/timespan-normalization-spacy
6
+ Author: Ilie Cristian Dorobat
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.6
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: spacy>=3.0
14
+ Requires-Dist: py4j
15
+ Requires-Dist: langdetect
16
+ Dynamic: author
17
+ Dynamic: classifier
18
+ Dynamic: description
19
+ Dynamic: description-content-type
20
+ Dynamic: home-page
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
24
+
25
+ # Temporal Expressions Normalization spaCy (TeNs)
26
+
27
+ <b>Temporal Expressions Normalization spaCy (TeNs)</b> is a powerful pipeline component for spaCy that seamlessly
28
+ identifies and parses date entities in text. It leverages the <b>[Temporal Normalization Framework](
29
+ https://github.com/iliedorobat/timespan-normalization)</b> to recognize a wide variety of date formats using an
30
+ extensive set of regular expressions (RegEx), ensuring robust and adaptable date extraction across diverse
31
+ textual sources.
32
+
33
+ Unlike conventional solutions that primarily focus on well-structured date formats, TeNs excels in handling
34
+ real-world text by <b>identifying</b> not only standard date representations but also <b>abbreviated, informal, or even
35
+ misspelled temporal expressions.</b> This makes it particularly effective for processing noisy or unstructured data,
36
+ such as historical records, user-generated content, and scanned documents with OCR inaccuracies.
37
+
38
+ Moreover, TeNs is designed to <b>integrate seamlessly into existing NLP pipelines,</b> allowing for enhanced temporal
39
+ information processing in tasks such as event extraction, timeline construction, and knowledge graph population.
40
+ By providing a flexible and accurate approach to temporal data normalization, it significantly improves the
41
+ quality and reliability of date-related information extracted from text.
42
+
43
+ <b>Table I.</b> Types of temporal expressions which can be processed
44
+ <table>
45
+ <tr>
46
+ <th>Type of Temporal Expressions</th>
47
+ <th>Examples of Temporal Expressions*</th>
48
+ </tr>
49
+ <tr>
50
+ <td>dates</td>
51
+ <td>
52
+ YMD: 1881-08-31; 1857 mai 10; etc.<br/>
53
+ DMY: 09.11.1518; 1 noiembrie 1624; etc.<br/>
54
+ MY: ianuarie 632; etc.
55
+ </td>
56
+ </tr>
57
+ <tr>
58
+ <td>timespans</td>
59
+ <td>
60
+ centuries: s:; sc; se.; sec; sec.; secol; secolele; secolul; sex.<br/>
61
+ millenniums: mil; mil.; mileniul; mileniului; mileniile
62
+ </td>
63
+ </tr>
64
+ <tr>
65
+ <td>years</td>
66
+ <td>77; 78; 1652; [1873]; aproximativ 1834; cca. 1420; etc.</td>
67
+ </tr>
68
+ </table>
69
+ * The values are mentioned in the reference language – Romanian language
70
+
71
+
72
+
73
+ ## Getting started
74
+ To integrate TeNs into spaCy pipelines you need the following:
75
+
76
+ ### Prerequisites
77
+ - Python 3.x
78
+ - JRE 11+
79
+ - spaCy 3.x
80
+ - py4j 0.10.9.9
81
+ - langdetect 1.0.9
82
+
83
+ 1. Install python packages:
84
+ ```bash
85
+ pip install -r requirements.txt
86
+ ```
87
+
88
+ 2. Install [JDK 11](https://www.oracle.com/nl/java/technologies/javase/jdk11-archive-downloads.html) or [OpenJDK 11](https://openjdk.org/install/) (or newer versions)
89
+
90
+
91
+ ### Install
92
+ ```bash
93
+ pip install temporal-spacy
94
+ ```
95
+
96
+ ### Supported languages
97
+ - [Romanian](https://universaldependencies.org/tagset-conversion/ro-multext-uposf.html)
98
+
99
+
100
+
101
+ ## Usage
102
+ ***
103
+
104
+ ### Importing Modules & Defining Constants
105
+
106
+ ```python
107
+ import subprocess
108
+
109
+ import spacy
110
+
111
+ from temporal_normalization.commons.print_utils import console
112
+ from temporal_normalization.index import create_normalized_component, TemporalNormalization ## noqa: F401
113
+
114
+ LANG = "ro"
115
+ MODEL = "ro_core_news_sm"
116
+ TEXT_RO = ("Sec al II-lea a.ch. a fost o perioadă de mari schimbări. "
117
+ "În secolul XX, tehnologia a avansat semnificativ. "
118
+ "Sec. 21 este adesea asociat cu globalizarea rapidă.")
119
+ ```
120
+
121
+ ### Adding the Component to spaCy Pipeline
122
+ ```python
123
+ # Display a warning if the language of the text is not Romanian.
124
+ console.lang_warning(TEXT_RO, target_lang=LANG)
125
+
126
+ try:
127
+ # Load the spaCy model if it has already been downloaded
128
+ nlp = spacy.load(MODEL)
129
+ except OSError:
130
+ console.warning(f'Started downloading {MODEL}...')
131
+ # Download the Romanian model if it wasn't already downloaded
132
+ subprocess.run(["python", "-m", "spacy", "download", MODEL])
133
+ # Load the spaCy model
134
+ nlp = spacy.load(MODEL)
135
+
136
+ # Add "temporal_normalization" component to the spaCy pipeline
137
+ nlp.add_pipe("temporal_normalization", last=True)
138
+ ```
139
+
140
+ ### Processing Text with the Pipeline
141
+ ```python
142
+ doc = nlp(TEXT_RO)
143
+
144
+ # Display NLP-specific linguistic annotations
145
+ console.tokens_table(doc)
146
+ print()
147
+ ```
148
+
149
+ ### Accessing the Parsed Temporal Expressions
150
+ ```python
151
+ # Display information about the identified and normalized dates in the text.
152
+ for entity in doc.ents:
153
+ for edge in entity._.normalized.edges:
154
+ print(edge.serialize())
155
+ print()
156
+
157
+ print("Periods:")
158
+ for period in entity._.normalized.periods:
159
+ print(period.serialize("\t"))
160
+ print()
161
+ ```
162
+
163
+ ### Result
164
+ #### First Sentence
165
+ ```text
166
+ Start time:
167
+ Matched value: Sec al II-lea a.ch.
168
+ Matched Type: century
169
+ Normalized label: 2nd century BC
170
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
171
+ End time:
172
+ Matched value: Sec al II-lea a.ch.
173
+ Matched Type: century
174
+ Normalized label: 2nd century BC
175
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
176
+
177
+ Periods:
178
+ Matched value: Sec al II-lea a.ch.
179
+ Matched Type: century
180
+ Normalized label: 1st millennium BC
181
+ DBpedia uri: https://dbpedia.org/page/1st_millennium_BC
182
+
183
+ Matched value: Sec al II-lea a.ch.
184
+ Matched Type: century
185
+ Normalized label: 2nd century BC
186
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
187
+ ```
188
+
189
+ #### Second Sentence
190
+ ```text
191
+ Start time:
192
+ Matched value: secolul XX
193
+ Matched Type: century
194
+ Normalized label: 20th century
195
+ DBpedia uri: https://dbpedia.org/page/20th_century
196
+ End time:
197
+ Matched value: secolul XX
198
+ Matched Type: century
199
+ Normalized label: 20th century
200
+ DBpedia uri: https://dbpedia.org/page/20th_century
201
+
202
+ Periods:
203
+ Matched value: secolul XX
204
+ Matched Type: century
205
+ Normalized label: 2nd millennium
206
+ DBpedia uri: https://dbpedia.org/page/2nd_millennium
207
+
208
+ Matched value: secolul XX
209
+ Matched Type: century
210
+ Normalized label: 20th century
211
+ DBpedia uri: https://dbpedia.org/page/20th_century
212
+ ```
213
+
214
+ #### Third Sentence
215
+ ```text
216
+ Start time:
217
+ Matched value: Sec. 21
218
+ Matched Type: century
219
+ Normalized label: 21st century
220
+ DBpedia uri: https://dbpedia.org/page/21st_century
221
+ End time:
222
+ Matched value: Sec. 21
223
+ Matched Type: century
224
+ Normalized label: 21st century
225
+ DBpedia uri: https://dbpedia.org/page/21st_century
226
+
227
+ Periods:
228
+ Matched value: Sec. 21
229
+ Matched Type: century
230
+ Normalized label: 3rd millennium
231
+ DBpedia uri: https://dbpedia.org/page/3rd_millennium
232
+
233
+ Matched value: Sec. 21
234
+ Matched Type: century
235
+ Normalized label: 21st century
236
+ DBpedia uri: https://dbpedia.org/page/21st_century
237
+ ```
238
+
239
+
240
+
241
+ ## Publications
242
+ ECAI 2021: [The Power of Regular Expressions in Recognizing Dates and Epochs (2021)](https://ieeexplore.ieee.org/document/9515139)
243
+ ```
244
+ @inproceedings{9515139,
245
+ author={Dorobăț, Ilie Cristian and Posea, Vlad},
246
+ booktitle={2021 13th International Conference on Electronics, Computers and Artificial Intelligence (ECAI)},
247
+ title={The Power of Regular Expressions in Recognizing Dates and Epochs},
248
+ year={2021},
249
+ pages={1-3},
250
+ doi={10.1109/ECAI52376.2021.9515139}}
251
+ ```
@@ -0,0 +1,227 @@
1
+ # Temporal Expressions Normalization spaCy (TeNs)
2
+
3
+ <b>Temporal Expressions Normalization spaCy (TeNs)</b> is a powerful pipeline component for spaCy that seamlessly
4
+ identifies and parses date entities in text. It leverages the <b>[Temporal Normalization Framework](
5
+ https://github.com/iliedorobat/timespan-normalization)</b> to recognize a wide variety of date formats using an
6
+ extensive set of regular expressions (RegEx), ensuring robust and adaptable date extraction across diverse
7
+ textual sources.
8
+
9
+ Unlike conventional solutions that primarily focus on well-structured date formats, TeNs excels in handling
10
+ real-world text by <b>identifying</b> not only standard date representations but also <b>abbreviated, informal, or even
11
+ misspelled temporal expressions.</b> This makes it particularly effective for processing noisy or unstructured data,
12
+ such as historical records, user-generated content, and scanned documents with OCR inaccuracies.
13
+
14
+ Moreover, TeNs is designed to <b>integrate seamlessly into existing NLP pipelines,</b> allowing for enhanced temporal
15
+ information processing in tasks such as event extraction, timeline construction, and knowledge graph population.
16
+ By providing a flexible and accurate approach to temporal data normalization, it significantly improves the
17
+ quality and reliability of date-related information extracted from text.
18
+
19
+ <b>Table I.</b> Types of temporal expressions which can be processed
20
+ <table>
21
+ <tr>
22
+ <th>Type of Temporal Expressions</th>
23
+ <th>Examples of Temporal Expressions*</th>
24
+ </tr>
25
+ <tr>
26
+ <td>dates</td>
27
+ <td>
28
+ YMD: 1881-08-31; 1857 mai 10; etc.<br/>
29
+ DMY: 09.11.1518; 1 noiembrie 1624; etc.<br/>
30
+ MY: ianuarie 632; etc.
31
+ </td>
32
+ </tr>
33
+ <tr>
34
+ <td>timespans</td>
35
+ <td>
36
+ centuries: s:; sc; se.; sec; sec.; secol; secolele; secolul; sex.<br/>
37
+ millenniums: mil; mil.; mileniul; mileniului; mileniile
38
+ </td>
39
+ </tr>
40
+ <tr>
41
+ <td>years</td>
42
+ <td>77; 78; 1652; [1873]; aproximativ 1834; cca. 1420; etc.</td>
43
+ </tr>
44
+ </table>
45
+ * The values are mentioned in the reference language – Romanian language
46
+
47
+
48
+
49
+ ## Getting started
50
+ To integrate TeNs into spaCy pipelines you need the following:
51
+
52
+ ### Prerequisites
53
+ - Python 3.x
54
+ - JRE 11+
55
+ - spaCy 3.x
56
+ - py4j 0.10.9.9
57
+ - langdetect 1.0.9
58
+
59
+ 1. Install python packages:
60
+ ```bash
61
+ pip install -r requirements.txt
62
+ ```
63
+
64
+ 2. Install [JDK 11](https://www.oracle.com/nl/java/technologies/javase/jdk11-archive-downloads.html) or [OpenJDK 11](https://openjdk.org/install/) (or newer versions)
65
+
66
+
67
+ ### Install
68
+ ```bash
69
+ pip install temporal-spacy
70
+ ```
71
+
72
+ ### Supported languages
73
+ - [Romanian](https://universaldependencies.org/tagset-conversion/ro-multext-uposf.html)
74
+
75
+
76
+
77
+ ## Usage
78
+ ***
79
+
80
+ ### Importing Modules & Defining Constants
81
+
82
+ ```python
83
+ import subprocess
84
+
85
+ import spacy
86
+
87
+ from temporal_normalization.commons.print_utils import console
88
+ from temporal_normalization.index import create_normalized_component, TemporalNormalization ## noqa: F401
89
+
90
+ LANG = "ro"
91
+ MODEL = "ro_core_news_sm"
92
+ TEXT_RO = ("Sec al II-lea a.ch. a fost o perioadă de mari schimbări. "
93
+ "În secolul XX, tehnologia a avansat semnificativ. "
94
+ "Sec. 21 este adesea asociat cu globalizarea rapidă.")
95
+ ```
96
+
97
+ ### Adding the Component to spaCy Pipeline
98
+ ```python
99
+ # Display a warning if the language of the text is not Romanian.
100
+ console.lang_warning(TEXT_RO, target_lang=LANG)
101
+
102
+ try:
103
+ # Load the spaCy model if it has already been downloaded
104
+ nlp = spacy.load(MODEL)
105
+ except OSError:
106
+ console.warning(f'Started downloading {MODEL}...')
107
+ # Download the Romanian model if it wasn't already downloaded
108
+ subprocess.run(["python", "-m", "spacy", "download", MODEL])
109
+ # Load the spaCy model
110
+ nlp = spacy.load(MODEL)
111
+
112
+ # Add "temporal_normalization" component to the spaCy pipeline
113
+ nlp.add_pipe("temporal_normalization", last=True)
114
+ ```
115
+
116
+ ### Processing Text with the Pipeline
117
+ ```python
118
+ doc = nlp(TEXT_RO)
119
+
120
+ # Display NLP-specific linguistic annotations
121
+ console.tokens_table(doc)
122
+ print()
123
+ ```
124
+
125
+ ### Accessing the Parsed Temporal Expressions
126
+ ```python
127
+ # Display information about the identified and normalized dates in the text.
128
+ for entity in doc.ents:
129
+ for edge in entity._.normalized.edges:
130
+ print(edge.serialize())
131
+ print()
132
+
133
+ print("Periods:")
134
+ for period in entity._.normalized.periods:
135
+ print(period.serialize("\t"))
136
+ print()
137
+ ```
138
+
139
+ ### Result
140
+ #### First Sentence
141
+ ```text
142
+ Start time:
143
+ Matched value: Sec al II-lea a.ch.
144
+ Matched Type: century
145
+ Normalized label: 2nd century BC
146
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
147
+ End time:
148
+ Matched value: Sec al II-lea a.ch.
149
+ Matched Type: century
150
+ Normalized label: 2nd century BC
151
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
152
+
153
+ Periods:
154
+ Matched value: Sec al II-lea a.ch.
155
+ Matched Type: century
156
+ Normalized label: 1st millennium BC
157
+ DBpedia uri: https://dbpedia.org/page/1st_millennium_BC
158
+
159
+ Matched value: Sec al II-lea a.ch.
160
+ Matched Type: century
161
+ Normalized label: 2nd century BC
162
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
163
+ ```
164
+
165
+ #### Second Sentence
166
+ ```text
167
+ Start time:
168
+ Matched value: secolul XX
169
+ Matched Type: century
170
+ Normalized label: 20th century
171
+ DBpedia uri: https://dbpedia.org/page/20th_century
172
+ End time:
173
+ Matched value: secolul XX
174
+ Matched Type: century
175
+ Normalized label: 20th century
176
+ DBpedia uri: https://dbpedia.org/page/20th_century
177
+
178
+ Periods:
179
+ Matched value: secolul XX
180
+ Matched Type: century
181
+ Normalized label: 2nd millennium
182
+ DBpedia uri: https://dbpedia.org/page/2nd_millennium
183
+
184
+ Matched value: secolul XX
185
+ Matched Type: century
186
+ Normalized label: 20th century
187
+ DBpedia uri: https://dbpedia.org/page/20th_century
188
+ ```
189
+
190
+ #### Third Sentence
191
+ ```text
192
+ Start time:
193
+ Matched value: Sec. 21
194
+ Matched Type: century
195
+ Normalized label: 21st century
196
+ DBpedia uri: https://dbpedia.org/page/21st_century
197
+ End time:
198
+ Matched value: Sec. 21
199
+ Matched Type: century
200
+ Normalized label: 21st century
201
+ DBpedia uri: https://dbpedia.org/page/21st_century
202
+
203
+ Periods:
204
+ Matched value: Sec. 21
205
+ Matched Type: century
206
+ Normalized label: 3rd millennium
207
+ DBpedia uri: https://dbpedia.org/page/3rd_millennium
208
+
209
+ Matched value: Sec. 21
210
+ Matched Type: century
211
+ Normalized label: 21st century
212
+ DBpedia uri: https://dbpedia.org/page/21st_century
213
+ ```
214
+
215
+
216
+
217
+ ## Publications
218
+ ECAI 2021: [The Power of Regular Expressions in Recognizing Dates and Epochs (2021)](https://ieeexplore.ieee.org/document/9515139)
219
+ ```
220
+ @inproceedings{9515139,
221
+ author={Dorobăț, Ilie Cristian and Posea, Vlad},
222
+ booktitle={2021 13th International Conference on Electronics, Computers and Artificial Intelligence (ECAI)},
223
+ title={The Power of Regular Expressions in Recognizing Dates and Epochs},
224
+ year={2021},
225
+ pages={1-3},
226
+ doi={10.1109/ECAI52376.2021.9515139}}
227
+ ```
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,27 @@
1
+ from setuptools import setup, find_packages
2
+
3
+ setup(
4
+ name="temporal_normalization_spacy",
5
+ version="1.0.0",
6
+ author="Ilie Cristian Dorobat",
7
+ description="A spaCy plugin for identifying and parsing historical data in Romanian texts",
8
+ long_description=open("README.md").read(),
9
+ long_description_content_type="text/markdown",
10
+ url="https://github.com/iliedorobat/timespan-normalization-spacy",
11
+ packages=find_packages(),
12
+ include_package_data=True,
13
+ package_data={
14
+ "temporal_normalization.libs": ["temporal-normalization-1.6.jar"],
15
+ },
16
+ install_requires=[
17
+ "spacy>=3.0",
18
+ "py4j",
19
+ "langdetect"
20
+ ],
21
+ classifiers=[
22
+ "Programming Language :: Python :: 3",
23
+ "License :: OSI Approved :: MIT License",
24
+ "Operating System :: OS Independent",
25
+ ],
26
+ python_requires=">=3.6",
27
+ )
@@ -0,0 +1,5 @@
1
+ from .commons.print_utils import *
2
+ from .commons.temporal_models import *
3
+ from .commons.temporal_types import *
4
+ from .process.java_process import *
5
+ from .index import TemporalNormalization
@@ -0,0 +1,3 @@
1
+ from .print_utils import *
2
+ from .temporal_models import *
3
+ from .temporal_types import *
@@ -0,0 +1,98 @@
1
+ from datetime import datetime
2
+
3
+ from langdetect import detect
4
+
5
+
6
+ # https://godoc.org/github.com/whitedevops/colors
7
+ class COLORS:
8
+ BLUE = "\033[34m"
9
+ CYAN = "\033[36m"
10
+ LIGHT_CYAN = "\033[96m"
11
+ LIGHT_YELLOW = "\033[93m"
12
+ LIGHT_RED = "\033[91m"
13
+ RED = "\033[31m"
14
+ RESET_ALL = '\033[0m'
15
+
16
+
17
+ # https://stackoverflow.com/questions/287871/how-to-print-colored-text-in-python#answer-287944
18
+ class console:
19
+ @staticmethod
20
+ def display(message: str, color: str, alert: str, show_time: bool = True):
21
+ if show_time:
22
+ print(f'{color}{datetime.now().replace(microsecond=0)} {alert}: {message}{COLORS.RESET_ALL}')
23
+ else:
24
+ print(f'{color}{message}{COLORS.RESET_ALL}')
25
+
26
+ @staticmethod
27
+ def debug(message: str, show_time: bool = True):
28
+ console.display(message, COLORS.CYAN, "DEBUG", show_time)
29
+
30
+ @staticmethod
31
+ def log(message: str, show_time: bool = True):
32
+ console.display(message, COLORS.BLUE, "LOG", show_time)
33
+
34
+ @staticmethod
35
+ def info(message: str, show_time: bool = True):
36
+ console.display(message, COLORS.LIGHT_CYAN, "INFO", show_time)
37
+
38
+ @staticmethod
39
+ def warning(message: str, show_time: bool = True):
40
+ console.display(message, COLORS.LIGHT_YELLOW, "WARNING", show_time)
41
+
42
+ @staticmethod
43
+ def error(message: str, show_time: bool = True):
44
+ console.display(message, COLORS.RED, "ERROR", show_time)
45
+
46
+ @staticmethod
47
+ def lang_warning(query: str, target_lang: str):
48
+ if detect(query) != target_lang:
49
+ console.warning(
50
+ f'Detected language: "{detect(query)}" but required: "{target_lang}"'
51
+ )
52
+ @staticmethod
53
+ def tokens_table(document):
54
+ console.info(
55
+ f'-------------------------------------------------------------------------------------------------------'
56
+ f'\n{"Token":{15}}|{"Lemma":{15}}|{"POS":{10}}|{"TAG":{10}}|'
57
+ f'{"DEP":{10}}|{"shape_":{15}}|{"is_alpha":{10}}',
58
+ show_time=False
59
+ )
60
+ console.info(
61
+ '-------------------------------------------------------------------------------------------------------',
62
+ show_time=False
63
+ )
64
+ for token in document:
65
+ console.info(
66
+ f'{token.text:{15}}|{token.lemma_:{15}}|{token.pos_:{10}}|{token.tag_:{10}}|{token.dep_:{10}}|'
67
+ f'{token.shape_:{15}}|{token.is_alpha:{10}}',
68
+ show_time=False
69
+ )
70
+ console.info(
71
+ '-------------------------------------------------------------------------------------------------------',
72
+ show_time=False
73
+ )
74
+ console.info(f'sentence: {document}', show_time=False)
75
+
76
+ @staticmethod
77
+ def deps_list(document):
78
+ separator = ''
79
+ for i in range(130):
80
+ separator += '-'
81
+
82
+ console.info(
83
+ f'{separator}\n'
84
+ f' '
85
+ f'{"Token":{15}}|{"Governor":{10}}|{"Root Node":{10}}|'
86
+ f'{"Lefts":{20}}|{"Rights":{20}}|'
87
+ f'{"Lemma":{15}}|{"POS":{10}}|{"TAG":{10}}|{"DEP":{10}}'
88
+ )
89
+ console.info(separator)
90
+ for token in document:
91
+ console.info(
92
+ f' '
93
+ f'{token.text:{15}}|{token.head.text:{10}}|{str(token == token.head):{10}}|'
94
+ f'{str(list(token.lefts)):{20}}|{str(list(token.rights)):{20}}|'
95
+ f'{token.lemma_:{15}}|{token.pos_:{10}}|{token.tag_:{10}}|{token.dep_:{10}}'
96
+ )
97
+ console.info(separator)
98
+ console.info(f'sentence: {document}')
@@ -0,0 +1,105 @@
1
+ import json
2
+ from py4j.java_gateway import JavaObject
3
+
4
+ from temporal_normalization.commons.temporal_types import TemporalType
5
+
6
+
7
+ class TemporalExpression:
8
+ """
9
+ A model representing a temporal expression, extracted and processed from a Java object.
10
+
11
+ Attributes:
12
+ is_valid (bool): A flag that specifies whether the text processed through timespan-normalization library is a temporal expression.
13
+ initial (str or None): The original temporal expression before processing.
14
+ edges (list[EdgeModel]): A list of temporal intervals represented as edges.
15
+ periods (list[DBpediaModel]): A list of normalized DBpedia entities extracted from the expression.
16
+ matches (list[str]): A unique list of matched values found in the normalized entities.
17
+ """
18
+
19
+ def __init__(self, java_object: JavaObject):
20
+ serialize = java_object.serialize()
21
+ json_obj = json.loads(serialize)
22
+
23
+ self.is_valid = TemporalExpression.is_valid_json(json_obj)
24
+ self.initial: str | None = json_obj["initial"] if self.is_valid else None
25
+ self.edges: list[EdgeModel] = [
26
+ EdgeModel(item) for item in json_obj["edges"]
27
+ ] if self.is_valid else []
28
+ self.periods: list[DBpediaModel] = [
29
+ DBpediaModel(item) for item in json_obj["periods"]
30
+ ] if self.is_valid else []
31
+ self.matches: list[str] = list(
32
+ set(
33
+ [item.matched_value for item in self.periods]
34
+ )
35
+ )
36
+
37
+ def __str__(self):
38
+ if self.initial is None:
39
+ return "TemporalExpression(None)"
40
+
41
+ return f"TemporalExpression({self.initial})"
42
+
43
+ def __repr__(self):
44
+ return self.initial
45
+
46
+ @staticmethod
47
+ def is_valid_json(json_obj) -> bool:
48
+ return ("initial" in json_obj
49
+ and "edges" in json_obj
50
+ and "periods" in json_obj)
51
+
52
+
53
+ class DBpediaModel:
54
+ """
55
+ A model representing an entity from DBpedia, storing key attributes related to the entity.
56
+
57
+ Attributes:
58
+ uri (str): The unique identifier (URI) of the DBpedia entity.
59
+ label (str): A human-readable name for the entity.
60
+ matched_value (str): The original matched value from the input data.
61
+ matched_type (TemporalType or None): The temporal type of the entity, if applicable.
62
+ """
63
+
64
+ def __init__(self, data: dict):
65
+ self.uri: str = data["uri"] if "uri" in data else None
66
+ self.label: str = data["label"] if "label" in data else None
67
+ self.matched_value: str = data["matchedValue"] if "matchedValue" in data else None
68
+ try:
69
+ self.matched_type: TemporalType = TemporalType(data["matchedType"]) if "matchedType" in data else None
70
+ except ValueError:
71
+ self.matched_type = None
72
+
73
+ def __repr__(self):
74
+ return f"DBpediaModel(label={self.label}, matched_value={self.matched_value})"
75
+
76
+ def serialize(self, indent: str = ""):
77
+ return (f"{indent}Matched value: {self.matched_value}\n"
78
+ f"{indent}Matched Type: {self.matched_type.value if self.matched_type else None}\n"
79
+ f"{indent}Normalized label: {self.label}\n"
80
+ f"{indent}DBpedia uri: {self.uri}")
81
+
82
+
83
+ class EdgeModel:
84
+ """
85
+ A model representing time interval represented as DBpedia entities.
86
+ This edge represents the starting and ending points of a time period.
87
+
88
+ Attributes:
89
+ start (DBpediaModel): The starting entity of the time period.
90
+ end (DBpediaModel): The ending entity of the time period.
91
+ """
92
+
93
+ def __init__(self, data: dict):
94
+ self.start: DBpediaModel = DBpediaModel(data["start"]) if "start" in data else None
95
+ self.end: DBpediaModel = DBpediaModel(data["end"]) if "end" in data else None
96
+
97
+ def __repr__(self):
98
+ return f"EdgeModel(start={self.start}, end={self.end})"
99
+
100
+ def serialize(self, indent: str = ""):
101
+ start = self.start.serialize("\t")
102
+ end = self.end.serialize("\t")
103
+
104
+ return (f"{indent}Start time:\n{start}\n"
105
+ f"{indent}End time:\n{end}")
@@ -0,0 +1,10 @@
1
+ from enum import Enum
2
+
3
+
4
+ class TemporalType(Enum):
5
+ CENTURY = "century"
6
+ DATE = "date"
7
+ EPOCH = "epoch"
8
+ MILLENNIUM = "millennium"
9
+ UNKNOWN = "unknown"
10
+ YEAR = "year"
@@ -0,0 +1,88 @@
1
+ import os
2
+ import re
3
+ import unicodedata
4
+
5
+ from spacy import Language
6
+ from spacy.tokens import Doc, Span
7
+
8
+ from temporal_normalization.commons.temporal_models import TemporalExpression
9
+ from temporal_normalization.process.java_process import start_process
10
+
11
+ try:
12
+ @Language.factory("temporal_normalization")
13
+ def create_normalized_component(nlp, name):
14
+ return TemporalNormalization(nlp, name)
15
+ except AttributeError:
16
+ # spaCy 2.x
17
+ pass
18
+
19
+
20
+ class TemporalNormalization:
21
+ __FIELD = "normalized"
22
+
23
+ def __init__(self, nlp: Language, name: str):
24
+ Span.set_extension("normalized", default=None, force=True)
25
+ self.nlp = nlp
26
+
27
+ def __call__(self, doc: Doc) -> Doc:
28
+ jar_path = os.path.join(
29
+ os.path.dirname(__file__),
30
+ 'libs/temporal-normalization-1.6.jar'
31
+ )
32
+
33
+ expressions: list[TemporalExpression] = []
34
+ start_process(doc, expressions, jar_path)
35
+ str_matches: list[str] = _prepare_str_patterns(expressions)
36
+
37
+ _retokenize(doc, str_matches, expressions)
38
+
39
+ return doc
40
+
41
+
42
+ def _prepare_str_patterns(expressions: list[TemporalExpression]) -> list[str]:
43
+ matches: list[str] = []
44
+
45
+ for expression in expressions:
46
+ for match in expression.matches:
47
+ matches.append(match)
48
+
49
+ return matches
50
+
51
+
52
+ def _retokenize(doc: Doc, str_matches: list[str], expressions: list[TemporalExpression]) -> None:
53
+ regex_matches: list[str] = [fr"{item}" for item in str_matches]
54
+ pattern = f"({'|'.join(regex_matches)})"
55
+ matches = list(re.finditer(pattern, remove_accents(doc.text), re.IGNORECASE)) if len(regex_matches) > 0 else []
56
+
57
+ with doc.retokenize() as retokenizer:
58
+ for match in matches:
59
+ start_char, end_char = match.start(), match.end()
60
+ start_token, end_token = None, None
61
+
62
+ for token in doc:
63
+ if token.idx == start_char:
64
+ start_token = token.i
65
+ if token.idx + len(token.text) == end_char:
66
+ end_token = token.i
67
+
68
+ if start_token is not None and end_token is not None:
69
+ entity = Span(doc, start_token, end_token + 1, label="DATETIME")
70
+ expression = next((item for item in expressions if remove_accents(entity.text) in item.matches), None)
71
+
72
+ if expression:
73
+ entity._.set("normalized", expression)
74
+
75
+ retokenizer.merge(entity)
76
+ else:
77
+ print(f"Warning: Could not find tokens for match '{match.group()}' at {start_char}-{end_char}")
78
+
79
+
80
+ def remove_accents(input_str):
81
+ # Normalize the input string to NFD form (decomposed)
82
+ nfkd_form = unicodedata.normalize('NFD', input_str)
83
+ # Filter out characters that are combining accents (category 'Mn' stands for Non-spacing Mark)
84
+ return ''.join([c for c in nfkd_form if unicodedata.category(c) != 'Mn'])
85
+
86
+
87
+ if __name__ == "__main__":
88
+ pass
@@ -0,0 +1 @@
1
+ from .java_process import *
@@ -0,0 +1,87 @@
1
+ import re
2
+ import shutil
3
+ import subprocess
4
+
5
+ from py4j.java_gateway import JavaGateway
6
+ from py4j.protocol import Py4JNetworkError
7
+ from spacy.tokens import Doc
8
+
9
+ from temporal_normalization.commons.print_utils import console
10
+ from temporal_normalization.commons.temporal_models import TemporalExpression
11
+
12
+
13
+ def start_process(doc: Doc, expressions: list[TemporalExpression], jar_path):
14
+ check_java_version()
15
+
16
+ java_process = subprocess.Popen(
17
+ ["java", "-jar", jar_path],
18
+ stdout=subprocess.PIPE,
19
+ stderr=subprocess.PIPE,
20
+ text=True
21
+ )
22
+
23
+ for line in java_process.stdout:
24
+ if "Gateway Server Started..." in line:
25
+ print(line.strip())
26
+ break
27
+
28
+ gateway = gateway_conn(doc, expressions)
29
+
30
+ try:
31
+ # Proper way to shut down Py4J
32
+ gateway.shutdown()
33
+ print("Python connection closed.")
34
+ except Py4JNetworkError:
35
+ print("Java process already shut down.")
36
+
37
+ # Terminate Java process
38
+ java_process.terminate()
39
+ print("Java server is shutting down...")
40
+
41
+
42
+ def gateway_conn(doc: Doc, expressions: list[TemporalExpression]) -> JavaGateway:
43
+ """Connect to the running Py4J Gateway"""
44
+
45
+ gateway = JavaGateway()
46
+ print("Python connection established.")
47
+
48
+ if isinstance(doc, Doc):
49
+ java_object = gateway.jvm.ro.webdata.normalization.timespan.ro.TimeExpression(doc.text, False, "\n")
50
+ time_expression = TemporalExpression(java_object)
51
+
52
+ if time_expression.is_valid:
53
+ expressions.append(time_expression)
54
+
55
+ return gateway
56
+
57
+
58
+ def check_java_version():
59
+ min_version = 11
60
+ java_path = shutil.which("java")
61
+
62
+ try:
63
+ if java_path:
64
+ # Run the command to check the Java version
65
+ result = subprocess.run([java_path, "-version"], capture_output=True, text=True)
66
+
67
+ # Print the version information (Java version is printed to stderr)
68
+ if result.returncode == 0:
69
+ version_output = result.stderr
70
+ match = re.search(r'version "(\d+\.\d+)', version_output)
71
+
72
+ if match:
73
+ crr_version = float(match.group(1))
74
+ if crr_version < min_version:
75
+ console.error(f"Java {crr_version} is installed, but version {min_version} is required.")
76
+ else:
77
+ console.error("Could not extract Java version.")
78
+ else:
79
+ console.error("Error occurred while checking the version.")
80
+ else:
81
+ console.error("Java not found.")
82
+ except Exception as e:
83
+ console.error(e.__str__())
84
+
85
+
86
+ if __name__ == "__main__":
87
+ pass
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.2
2
+ Name: temporal_normalization_spacy
3
+ Version: 1.0.0
4
+ Summary: A spaCy plugin for identifying and parsing historical data in Romanian texts
5
+ Home-page: https://github.com/iliedorobat/timespan-normalization-spacy
6
+ Author: Ilie Cristian Dorobat
7
+ Classifier: Programming Language :: Python :: 3
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Operating System :: OS Independent
10
+ Requires-Python: >=3.6
11
+ Description-Content-Type: text/markdown
12
+ License-File: LICENSE
13
+ Requires-Dist: spacy>=3.0
14
+ Requires-Dist: py4j
15
+ Requires-Dist: langdetect
16
+ Dynamic: author
17
+ Dynamic: classifier
18
+ Dynamic: description
19
+ Dynamic: description-content-type
20
+ Dynamic: home-page
21
+ Dynamic: requires-dist
22
+ Dynamic: requires-python
23
+ Dynamic: summary
24
+
25
+ # Temporal Expressions Normalization spaCy (TeNs)
26
+
27
+ <b>Temporal Expressions Normalization spaCy (TeNs)</b> is a powerful pipeline component for spaCy that seamlessly
28
+ identifies and parses date entities in text. It leverages the <b>[Temporal Normalization Framework](
29
+ https://github.com/iliedorobat/timespan-normalization)</b> to recognize a wide variety of date formats using an
30
+ extensive set of regular expressions (RegEx), ensuring robust and adaptable date extraction across diverse
31
+ textual sources.
32
+
33
+ Unlike conventional solutions that primarily focus on well-structured date formats, TeNs excels in handling
34
+ real-world text by <b>identifying</b> not only standard date representations but also <b>abbreviated, informal, or even
35
+ misspelled temporal expressions.</b> This makes it particularly effective for processing noisy or unstructured data,
36
+ such as historical records, user-generated content, and scanned documents with OCR inaccuracies.
37
+
38
+ Moreover, TeNs is designed to <b>integrate seamlessly into existing NLP pipelines,</b> allowing for enhanced temporal
39
+ information processing in tasks such as event extraction, timeline construction, and knowledge graph population.
40
+ By providing a flexible and accurate approach to temporal data normalization, it significantly improves the
41
+ quality and reliability of date-related information extracted from text.
42
+
43
+ <b>Table I.</b> Types of temporal expressions which can be processed
44
+ <table>
45
+ <tr>
46
+ <th>Type of Temporal Expressions</th>
47
+ <th>Examples of Temporal Expressions*</th>
48
+ </tr>
49
+ <tr>
50
+ <td>dates</td>
51
+ <td>
52
+ YMD: 1881-08-31; 1857 mai 10; etc.<br/>
53
+ DMY: 09.11.1518; 1 noiembrie 1624; etc.<br/>
54
+ MY: ianuarie 632; etc.
55
+ </td>
56
+ </tr>
57
+ <tr>
58
+ <td>timespans</td>
59
+ <td>
60
+ centuries: s:; sc; se.; sec; sec.; secol; secolele; secolul; sex.<br/>
61
+ millenniums: mil; mil.; mileniul; mileniului; mileniile
62
+ </td>
63
+ </tr>
64
+ <tr>
65
+ <td>years</td>
66
+ <td>77; 78; 1652; [1873]; aproximativ 1834; cca. 1420; etc.</td>
67
+ </tr>
68
+ </table>
69
+ * The values are mentioned in the reference language – Romanian language
70
+
71
+
72
+
73
+ ## Getting started
74
+ To integrate TeNs into spaCy pipelines you need the following:
75
+
76
+ ### Prerequisites
77
+ - Python 3.x
78
+ - JRE 11+
79
+ - spaCy 3.x
80
+ - py4j 0.10.9.9
81
+ - langdetect 1.0.9
82
+
83
+ 1. Install python packages:
84
+ ```bash
85
+ pip install -r requirements.txt
86
+ ```
87
+
88
+ 2. Install [JDK 11](https://www.oracle.com/nl/java/technologies/javase/jdk11-archive-downloads.html) or [OpenJDK 11](https://openjdk.org/install/) (or newer versions)
89
+
90
+
91
+ ### Install
92
+ ```bash
93
+ pip install temporal-spacy
94
+ ```
95
+
96
+ ### Supported languages
97
+ - [Romanian](https://universaldependencies.org/tagset-conversion/ro-multext-uposf.html)
98
+
99
+
100
+
101
+ ## Usage
102
+ ***
103
+
104
+ ### Importing Modules & Defining Constants
105
+
106
+ ```python
107
+ import subprocess
108
+
109
+ import spacy
110
+
111
+ from temporal_normalization.commons.print_utils import console
112
+ from temporal_normalization.index import create_normalized_component, TemporalNormalization ## noqa: F401
113
+
114
+ LANG = "ro"
115
+ MODEL = "ro_core_news_sm"
116
+ TEXT_RO = ("Sec al II-lea a.ch. a fost o perioadă de mari schimbări. "
117
+ "În secolul XX, tehnologia a avansat semnificativ. "
118
+ "Sec. 21 este adesea asociat cu globalizarea rapidă.")
119
+ ```
120
+
121
+ ### Adding the Component to spaCy Pipeline
122
+ ```python
123
+ # Display a warning if the language of the text is not Romanian.
124
+ console.lang_warning(TEXT_RO, target_lang=LANG)
125
+
126
+ try:
127
+ # Load the spaCy model if it has already been downloaded
128
+ nlp = spacy.load(MODEL)
129
+ except OSError:
130
+ console.warning(f'Started downloading {MODEL}...')
131
+ # Download the Romanian model if it wasn't already downloaded
132
+ subprocess.run(["python", "-m", "spacy", "download", MODEL])
133
+ # Load the spaCy model
134
+ nlp = spacy.load(MODEL)
135
+
136
+ # Add "temporal_normalization" component to the spaCy pipeline
137
+ nlp.add_pipe("temporal_normalization", last=True)
138
+ ```
139
+
140
+ ### Processing Text with the Pipeline
141
+ ```python
142
+ doc = nlp(TEXT_RO)
143
+
144
+ # Display NLP-specific linguistic annotations
145
+ console.tokens_table(doc)
146
+ print()
147
+ ```
148
+
149
+ ### Accessing the Parsed Temporal Expressions
150
+ ```python
151
+ # Display information about the identified and normalized dates in the text.
152
+ for entity in doc.ents:
153
+ for edge in entity._.normalized.edges:
154
+ print(edge.serialize())
155
+ print()
156
+
157
+ print("Periods:")
158
+ for period in entity._.normalized.periods:
159
+ print(period.serialize("\t"))
160
+ print()
161
+ ```
162
+
163
+ ### Result
164
+ #### First Sentence
165
+ ```text
166
+ Start time:
167
+ Matched value: Sec al II-lea a.ch.
168
+ Matched Type: century
169
+ Normalized label: 2nd century BC
170
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
171
+ End time:
172
+ Matched value: Sec al II-lea a.ch.
173
+ Matched Type: century
174
+ Normalized label: 2nd century BC
175
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
176
+
177
+ Periods:
178
+ Matched value: Sec al II-lea a.ch.
179
+ Matched Type: century
180
+ Normalized label: 1st millennium BC
181
+ DBpedia uri: https://dbpedia.org/page/1st_millennium_BC
182
+
183
+ Matched value: Sec al II-lea a.ch.
184
+ Matched Type: century
185
+ Normalized label: 2nd century BC
186
+ DBpedia uri: https://dbpedia.org/page/2nd_century_BC
187
+ ```
188
+
189
+ #### Second Sentence
190
+ ```text
191
+ Start time:
192
+ Matched value: secolul XX
193
+ Matched Type: century
194
+ Normalized label: 20th century
195
+ DBpedia uri: https://dbpedia.org/page/20th_century
196
+ End time:
197
+ Matched value: secolul XX
198
+ Matched Type: century
199
+ Normalized label: 20th century
200
+ DBpedia uri: https://dbpedia.org/page/20th_century
201
+
202
+ Periods:
203
+ Matched value: secolul XX
204
+ Matched Type: century
205
+ Normalized label: 2nd millennium
206
+ DBpedia uri: https://dbpedia.org/page/2nd_millennium
207
+
208
+ Matched value: secolul XX
209
+ Matched Type: century
210
+ Normalized label: 20th century
211
+ DBpedia uri: https://dbpedia.org/page/20th_century
212
+ ```
213
+
214
+ #### Third Sentence
215
+ ```text
216
+ Start time:
217
+ Matched value: Sec. 21
218
+ Matched Type: century
219
+ Normalized label: 21st century
220
+ DBpedia uri: https://dbpedia.org/page/21st_century
221
+ End time:
222
+ Matched value: Sec. 21
223
+ Matched Type: century
224
+ Normalized label: 21st century
225
+ DBpedia uri: https://dbpedia.org/page/21st_century
226
+
227
+ Periods:
228
+ Matched value: Sec. 21
229
+ Matched Type: century
230
+ Normalized label: 3rd millennium
231
+ DBpedia uri: https://dbpedia.org/page/3rd_millennium
232
+
233
+ Matched value: Sec. 21
234
+ Matched Type: century
235
+ Normalized label: 21st century
236
+ DBpedia uri: https://dbpedia.org/page/21st_century
237
+ ```
238
+
239
+
240
+
241
+ ## Publications
242
+ ECAI 2021: [The Power of Regular Expressions in Recognizing Dates and Epochs (2021)](https://ieeexplore.ieee.org/document/9515139)
243
+ ```
244
+ @inproceedings{9515139,
245
+ author={Dorobăț, Ilie Cristian and Posea, Vlad},
246
+ booktitle={2021 13th International Conference on Electronics, Computers and Artificial Intelligence (ECAI)},
247
+ title={The Power of Regular Expressions in Recognizing Dates and Epochs},
248
+ year={2021},
249
+ pages={1-3},
250
+ doi={10.1109/ECAI52376.2021.9515139}}
251
+ ```
@@ -0,0 +1,18 @@
1
+ LICENSE
2
+ MANIFEST.in
3
+ README.md
4
+ setup.py
5
+ temporal_normalization/__init__.py
6
+ temporal_normalization/index.py
7
+ temporal_normalization/commons/__init__.py
8
+ temporal_normalization/commons/print_utils.py
9
+ temporal_normalization/commons/temporal_models.py
10
+ temporal_normalization/commons/temporal_types.py
11
+ temporal_normalization/libs/temporal-normalization-1.6.jar
12
+ temporal_normalization/process/__init__.py
13
+ temporal_normalization/process/java_process.py
14
+ temporal_normalization_spacy.egg-info/PKG-INFO
15
+ temporal_normalization_spacy.egg-info/SOURCES.txt
16
+ temporal_normalization_spacy.egg-info/dependency_links.txt
17
+ temporal_normalization_spacy.egg-info/requires.txt
18
+ temporal_normalization_spacy.egg-info/top_level.txt