Spaces:
Running
Running
Lakoc
commited on
Commit
·
605b3ec
0
Parent(s):
Initial commit
Browse files- app.py +122 -0
- content.py +51 -0
- requirements.txt +10 -0
- tasks_metadata.json +10 -0
- txt_norm/__init__.py +18 -0
- txt_norm/basic.py +85 -0
- txt_norm/english.json +1739 -0
- txt_norm/english.py +691 -0
- txt_norm/pre_english.json +5 -0
- utils.py +282 -0
app.py
ADDED
@@ -0,0 +1,122 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
|
3 |
+
import gradio as gr
|
4 |
+
from gradio_modal import Modal
|
5 |
+
|
6 |
+
from content import HEADER_MARKDOWN, LEADERBOARD_TAB_TITLE_MARKDOWN, SUBMISSION_TAB_TITLE_MARKDOWN
|
7 |
+
from leaderboard_server import LeaderboardServer
|
8 |
+
|
9 |
+
# Initialize server and task list
|
10 |
+
server = LeaderboardServer()
|
11 |
+
TASKS = list(server.tasks_metadata.keys())
|
12 |
+
EXPECTED_TOKEN = os.environ.get("SUBMISSION_TOKEN")
|
13 |
+
|
14 |
+
|
15 |
+
def get_datasets_for_task(task):
|
16 |
+
path = os.path.join("references", task)
|
17 |
+
if not os.path.exists(path):
|
18 |
+
return []
|
19 |
+
return [f.replace(".json", "") for f in os.listdir(path) if f.endswith(".json")]
|
20 |
+
|
21 |
+
|
22 |
+
def update_datasets(task):
|
23 |
+
return gr.CheckboxGroup.update(choices=get_datasets_for_task(task), value=[])
|
24 |
+
|
25 |
+
|
26 |
+
def submit_model(task, datasets, hyp_file, submitted_by, model_id, token):
|
27 |
+
if not hyp_file:
|
28 |
+
return gr.update(visible=True, value="⚠️ Please upload a hypothesis file."), gr.update(), gr.update(selected=1)
|
29 |
+
|
30 |
+
if not submitted_by.strip() or not model_id.strip() or not token.strip():
|
31 |
+
return gr.update(visible=True, value="⚠️ All fields are required."), gr.update(), gr.update(selected=1)
|
32 |
+
|
33 |
+
if token.strip() != EXPECTED_TOKEN:
|
34 |
+
return gr.update(visible=True, value="❌ Invalid submission token."), gr.update(), gr.update(selected=1)
|
35 |
+
|
36 |
+
metadata = {
|
37 |
+
"submitted_by": submitted_by.strip(),
|
38 |
+
"model_id": model_id.strip()
|
39 |
+
}
|
40 |
+
leaderboard_df = server.get_leaderboard()
|
41 |
+
existing = leaderboard_df[
|
42 |
+
(leaderboard_df["Submitted by"] == submitted_by.strip()) &
|
43 |
+
(leaderboard_df["Model ID"] == model_id.strip())
|
44 |
+
]
|
45 |
+
if not existing.empty:
|
46 |
+
return gr.update(value="❌ A submission with this name and model ID already exists.", visible=True), \
|
47 |
+
gr.update(), gr.update(selected=1), gr.update(visible=False)
|
48 |
+
|
49 |
+
try:
|
50 |
+
server.prepare_model_for_submission(hyp_file.name, metadata, task, datasets)
|
51 |
+
server.update_leaderboard()
|
52 |
+
leaderboard_df = server.get_leaderboard()
|
53 |
+
return gr.update(visible=True, value="✅ Submission successful!"), leaderboard_df, gr.update(selected=0)
|
54 |
+
except Exception as e:
|
55 |
+
return gr.update(visible=True, value=f"❌ Error: {str(e)}"), gr.update(), gr.update(selected=1)
|
56 |
+
|
57 |
+
|
58 |
+
# Gradio UI
|
59 |
+
with gr.Blocks() as demo:
|
60 |
+
gr.Markdown(HEADER_MARKDOWN)
|
61 |
+
|
62 |
+
with gr.Tabs(selected=0) as tabs:
|
63 |
+
with gr.Tab("📈 Leaderboard"):
|
64 |
+
gr.Markdown(LEADERBOARD_TAB_TITLE_MARKDOWN)
|
65 |
+
leaderboard_output = gr.Dataframe(
|
66 |
+
value=server.get_leaderboard(),
|
67 |
+
interactive=False,
|
68 |
+
label="Leaderboard"
|
69 |
+
)
|
70 |
+
|
71 |
+
with gr.Tab("📤 Submit"):
|
72 |
+
gr.Markdown(SUBMISSION_TAB_TITLE_MARKDOWN)
|
73 |
+
|
74 |
+
with gr.Row():
|
75 |
+
task_dropdown = gr.Dropdown(choices=TASKS, value=TASKS[0], label="Select Task")
|
76 |
+
dataset_checkboxes = gr.CheckboxGroup(choices=get_datasets_for_task(TASKS[0]), label="Select Datasets")
|
77 |
+
task_dropdown.change(fn=update_datasets, inputs=task_dropdown, outputs=dataset_checkboxes)
|
78 |
+
|
79 |
+
with gr.Row():
|
80 |
+
submitted_by_input = gr.Text(label="Submitted by")
|
81 |
+
model_id_input = gr.Text(label="Model Identifier")
|
82 |
+
token_input = gr.Text(label="Submission Token", type="password")
|
83 |
+
|
84 |
+
hyp_file_upload = gr.File(label="Upload Hypothesis JSON", file_types=[".json"])
|
85 |
+
submit_btn = gr.Button("Submit")
|
86 |
+
with Modal("Submission Feedback", visible=False) as loading_msg:
|
87 |
+
feedback_text = gr.Text(visible=True, label="⏳ Processing your submission...")
|
88 |
+
|
89 |
+
with Modal("Submission Feedback", visible=False) as modal:
|
90 |
+
feedback_text = gr.Text(visible=True, label="")
|
91 |
+
|
92 |
+
submit_btn.click(
|
93 |
+
lambda: gr.update(visible=True), # Show loading
|
94 |
+
outputs=loading_msg
|
95 |
+
).then(
|
96 |
+
fn=submit_model,
|
97 |
+
inputs=[task_dropdown, dataset_checkboxes, hyp_file_upload, submitted_by_input, model_id_input,
|
98 |
+
token_input],
|
99 |
+
outputs=[feedback_text, leaderboard_output, tabs],
|
100 |
+
show_progress=True
|
101 |
+
).then(
|
102 |
+
lambda: gr.update(visible=False),
|
103 |
+
outputs=loading_msg
|
104 |
+
).then(
|
105 |
+
lambda: gr.update(visible=True),
|
106 |
+
outputs=modal
|
107 |
+
)
|
108 |
+
# submit_btn.click(
|
109 |
+
# fn=submit_model,
|
110 |
+
# inputs=[
|
111 |
+
# task_dropdown, dataset_checkboxes, hyp_file_upload,
|
112 |
+
# submitted_by_input, model_id_input, token_input
|
113 |
+
# ],
|
114 |
+
# outputs=[feedback_text, leaderboard_output, tabs],
|
115 |
+
# show_progress=True
|
116 |
+
# ).then(
|
117 |
+
# lambda: gr.update(visible=True),
|
118 |
+
# outputs=modal
|
119 |
+
# )
|
120 |
+
|
121 |
+
if __name__ == "__main__":
|
122 |
+
demo.launch()
|
content.py
ADDED
@@ -0,0 +1,51 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
This file contains the text content for the leaderboard client.
|
3 |
+
"""
|
4 |
+
HEADER_MARKDOWN = """
|
5 |
+
# EMMA JSALT25 Benchmark – Multi-Talker ASR Evaluation
|
6 |
+
|
7 |
+
Welcome to the official leaderboard for benchmarking **multi-talker ASR systems**, hosted by the **EMMA JSALT25 team**. This platform enables model submissions, comparisons, and evaluation on challenging multi-speaker scenarios.
|
8 |
+
"""
|
9 |
+
|
10 |
+
LEADERBOARD_TAB_TITLE_MARKDOWN = """
|
11 |
+
## Leaderboard
|
12 |
+
|
13 |
+
Below you’ll find the latest results submitted to the benchmark. Models are evaluated using **`meeteval`** with **TCP-WER (collar=5s)**.
|
14 |
+
"""
|
15 |
+
|
16 |
+
SUBMISSION_TAB_TITLE_MARKDOWN = """
|
17 |
+
## Submit Your Model
|
18 |
+
|
19 |
+
To submit your MT-ASR hypothesis to the benchmark, complete the form below:
|
20 |
+
|
21 |
+
- **Submitted by**: Your name or team identifier.
|
22 |
+
- **Model ID**: A unique identifier for your submission (used to track models on the leaderboard).
|
23 |
+
- **Hypothesis File**: Upload a **SegLST `.json` file** that includes **all segments across datasets** in a single list.
|
24 |
+
- **Task**: Choose the evaluation task (e.g., single-channel ground-truth diarization).
|
25 |
+
- **Datasets**: Select one or more datasets you wish to evaluate on.
|
26 |
+
|
27 |
+
📩 To enable submission, please [email the EMMA team](mailto:[email protected]) to receive a **submission token**.
|
28 |
+
|
29 |
+
After clicking **Submit**, your model will be evaluated and results displayed in the leaderboard.
|
30 |
+
"""
|
31 |
+
|
32 |
+
|
33 |
+
RANKING_AFTER_SUBMISSION_MARKDOWN = """
|
34 |
+
📊 Below is how your model compares after evaluation:
|
35 |
+
"""
|
36 |
+
|
37 |
+
SUBMISSION_DETAILS_MARKDOWN = """
|
38 |
+
⚠️ Are you sure you want to finalize your submission? This action is **irreversible** once submitted.
|
39 |
+
"""
|
40 |
+
|
41 |
+
MORE_DETAILS_MARKDOWN = """
|
42 |
+
## Model Metadata:
|
43 |
+
Detailed information about the selected submission.
|
44 |
+
"""
|
45 |
+
|
46 |
+
MODAL_SUBMIT_MARKDOWN = """
|
47 |
+
✅ Confirm Submission
|
48 |
+
|
49 |
+
Are you ready to submit your model for evaluation?
|
50 |
+
"""
|
51 |
+
|
requirements.txt
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
gradio
|
2 |
+
pandas
|
3 |
+
azure-cosmos
|
4 |
+
huggingface_hub
|
5 |
+
requests
|
6 |
+
Pyarrow
|
7 |
+
tabulate
|
8 |
+
simplejson
|
9 |
+
more-itertools
|
10 |
+
meeteval
|
tasks_metadata.json
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"tasks": {
|
3 |
+
"single_channel_gt": {
|
4 |
+
"name": "Single Channel - Ground Truth Diarization"
|
5 |
+
},
|
6 |
+
"single_channel_real": {
|
7 |
+
"name": "Single Channel - Real Diarization"
|
8 |
+
}
|
9 |
+
}
|
10 |
+
}
|
txt_norm/__init__.py
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
"""
|
2 |
+
NOTSOFAR adopts the same text normalizer as the CHiME-8 DASR track.
|
3 |
+
This code is aligned with the CHiME-8 repo:
|
4 |
+
https://github.com/chimechallenge/chime-utils/tree/main/chime_utils/text_norm
|
5 |
+
"""
|
6 |
+
import json
|
7 |
+
from .basic import BasicTextNormalizer as BasicTextNormalizer
|
8 |
+
from .english import EnglishTextNormalizer as EnglishTextNormalizerNSF
|
9 |
+
|
10 |
+
|
11 |
+
def get_text_norm(t_norm: str):
|
12 |
+
if t_norm == 'whisper':
|
13 |
+
SPELLING_CORRECTIONS = json.load(open('src/txt_norm/english.json'))
|
14 |
+
return EnglishTextNormalizer(SPELLING_CORRECTIONS)
|
15 |
+
elif t_norm == 'whisper_nsf':
|
16 |
+
return EnglishTextNormalizerNSF()
|
17 |
+
else:
|
18 |
+
return lambda x: x
|
txt_norm/basic.py
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
import unicodedata
|
3 |
+
|
4 |
+
import regex
|
5 |
+
|
6 |
+
# non-ASCII letters that are not separated by "NFKD" normalization
|
7 |
+
ADDITIONAL_DIACRITICS = {
|
8 |
+
"œ": "oe",
|
9 |
+
"Œ": "OE",
|
10 |
+
"ø": "o",
|
11 |
+
"Ø": "O",
|
12 |
+
"æ": "ae",
|
13 |
+
"Æ": "AE",
|
14 |
+
"ß": "ss",
|
15 |
+
"ẞ": "SS",
|
16 |
+
"đ": "d",
|
17 |
+
"Đ": "D",
|
18 |
+
"ð": "d",
|
19 |
+
"Ð": "D",
|
20 |
+
"þ": "th",
|
21 |
+
"Þ": "th",
|
22 |
+
"ł": "l",
|
23 |
+
"Ł": "L",
|
24 |
+
}
|
25 |
+
|
26 |
+
|
27 |
+
def remove_symbols_and_diacritics(s: str, keep=""):
|
28 |
+
"""
|
29 |
+
Replace any other markers, symbols, and punctuations with a space,
|
30 |
+
and drop any diacritics (category 'Mn' and some manual mappings)
|
31 |
+
"""
|
32 |
+
return "".join(
|
33 |
+
(
|
34 |
+
c
|
35 |
+
if c in keep
|
36 |
+
else (
|
37 |
+
ADDITIONAL_DIACRITICS[c]
|
38 |
+
if c in ADDITIONAL_DIACRITICS
|
39 |
+
else (
|
40 |
+
""
|
41 |
+
if unicodedata.category(c) == "Mn"
|
42 |
+
else " "
|
43 |
+
if unicodedata.category(c)[0] in "MSP"
|
44 |
+
else c
|
45 |
+
)
|
46 |
+
)
|
47 |
+
)
|
48 |
+
for c in unicodedata.normalize("NFKD", s)
|
49 |
+
)
|
50 |
+
|
51 |
+
|
52 |
+
def remove_symbols(s: str):
|
53 |
+
"""
|
54 |
+
Replace any other markers, symbols,
|
55 |
+
punctuations with a space, keeping diacritics
|
56 |
+
"""
|
57 |
+
return "".join(
|
58 |
+
" " if unicodedata.category(c)[0] in "MSP" else c
|
59 |
+
for c in unicodedata.normalize("NFKC", s)
|
60 |
+
)
|
61 |
+
|
62 |
+
|
63 |
+
class BasicTextNormalizer:
|
64 |
+
def __init__(self, remove_diacritics: bool = False, split_letters: bool = False):
|
65 |
+
self.clean = (
|
66 |
+
remove_symbols_and_diacritics if remove_diacritics else remove_symbols
|
67 |
+
)
|
68 |
+
self.split_letters = split_letters
|
69 |
+
|
70 |
+
def __call__(self, s: str):
|
71 |
+
s = s.lower()
|
72 |
+
# remove words between brackets
|
73 |
+
s = re.sub(r"[<\[][^>\]]*[>\]]", "", s)
|
74 |
+
# remove words between parenthesis
|
75 |
+
s = re.sub(r"\(([^)]+?)\)", "", s)
|
76 |
+
s = self.clean(s).lower()
|
77 |
+
|
78 |
+
if self.split_letters:
|
79 |
+
s = " ".join(regex.findall(r"\X", s, regex.U))
|
80 |
+
|
81 |
+
s = re.sub(
|
82 |
+
r"\s+", " ", s
|
83 |
+
) # replace any successive whitespace characters with a space
|
84 |
+
|
85 |
+
return s
|
txt_norm/english.json
ADDED
@@ -0,0 +1,1739 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"accessorise": "accessorize",
|
3 |
+
"accessorised": "accessorized",
|
4 |
+
"accessorises": "accessorizes",
|
5 |
+
"accessorising": "accessorizing",
|
6 |
+
"acclimatisation": "acclimatization",
|
7 |
+
"acclimatise": "acclimatize",
|
8 |
+
"acclimatised": "acclimatized",
|
9 |
+
"acclimatises": "acclimatizes",
|
10 |
+
"acclimatising": "acclimatizing",
|
11 |
+
"accoutrements": "accouterments",
|
12 |
+
"aeon": "eon",
|
13 |
+
"aeons": "eons",
|
14 |
+
"aerogramme": "aerogram",
|
15 |
+
"aerogrammes": "aerograms",
|
16 |
+
"aeroplane": "airplane",
|
17 |
+
"aeroplanes": "airplanes",
|
18 |
+
"aesthete": "esthete",
|
19 |
+
"aesthetes": "esthetes",
|
20 |
+
"aesthetic": "esthetic",
|
21 |
+
"aesthetically": "esthetically",
|
22 |
+
"aesthetics": "esthetics",
|
23 |
+
"aetiology": "etiology",
|
24 |
+
"ageing": "aging",
|
25 |
+
"aggrandisement": "aggrandizement",
|
26 |
+
"agonise": "agonize",
|
27 |
+
"agonised": "agonized",
|
28 |
+
"agonises": "agonizes",
|
29 |
+
"agonising": "agonizing",
|
30 |
+
"agonisingly": "agonizingly",
|
31 |
+
"almanack": "almanac",
|
32 |
+
"almanacks": "almanacs",
|
33 |
+
"aluminium": "aluminum",
|
34 |
+
"amortisable": "amortizable",
|
35 |
+
"amortisation": "amortization",
|
36 |
+
"amortisations": "amortizations",
|
37 |
+
"amortise": "amortize",
|
38 |
+
"amortised": "amortized",
|
39 |
+
"amortises": "amortizes",
|
40 |
+
"amortising": "amortizing",
|
41 |
+
"amphitheatre": "amphitheater",
|
42 |
+
"amphitheatres": "amphitheaters",
|
43 |
+
"anaemia": "anemia",
|
44 |
+
"anaemic": "anemic",
|
45 |
+
"anaesthesia": "anesthesia",
|
46 |
+
"anaesthetic": "anesthetic",
|
47 |
+
"anaesthetics": "anesthetics",
|
48 |
+
"anaesthetise": "anesthetize",
|
49 |
+
"anaesthetised": "anesthetized",
|
50 |
+
"anaesthetises": "anesthetizes",
|
51 |
+
"anaesthetising": "anesthetizing",
|
52 |
+
"anaesthetist": "anesthetist",
|
53 |
+
"anaesthetists": "anesthetists",
|
54 |
+
"anaesthetize": "anesthetize",
|
55 |
+
"anaesthetized": "anesthetized",
|
56 |
+
"anaesthetizes": "anesthetizes",
|
57 |
+
"anaesthetizing": "anesthetizing",
|
58 |
+
"analogue": "analog",
|
59 |
+
"analogues": "analogs",
|
60 |
+
"analyse": "analyze",
|
61 |
+
"analysed": "analyzed",
|
62 |
+
"analyses": "analyzes",
|
63 |
+
"analysing": "analyzing",
|
64 |
+
"anglicise": "anglicize",
|
65 |
+
"anglicised": "anglicized",
|
66 |
+
"anglicises": "anglicizes",
|
67 |
+
"anglicising": "anglicizing",
|
68 |
+
"annualised": "annualized",
|
69 |
+
"antagonise": "antagonize",
|
70 |
+
"antagonised": "antagonized",
|
71 |
+
"antagonises": "antagonizes",
|
72 |
+
"antagonising": "antagonizing",
|
73 |
+
"apologise": "apologize",
|
74 |
+
"apologised": "apologized",
|
75 |
+
"apologises": "apologizes",
|
76 |
+
"apologising": "apologizing",
|
77 |
+
"appal": "appall",
|
78 |
+
"appals": "appalls",
|
79 |
+
"appetiser": "appetizer",
|
80 |
+
"appetisers": "appetizers",
|
81 |
+
"appetising": "appetizing",
|
82 |
+
"appetisingly": "appetizingly",
|
83 |
+
"arbour": "arbor",
|
84 |
+
"arbours": "arbors",
|
85 |
+
"archeological": "archaeological",
|
86 |
+
"archaeologically": "archeologically",
|
87 |
+
"archaeologist": "archeologist",
|
88 |
+
"archaeologists": "archeologists",
|
89 |
+
"archaeology": "archeology",
|
90 |
+
"ardour": "ardor",
|
91 |
+
"armour": "armor",
|
92 |
+
"armoured": "armored",
|
93 |
+
"armourer": "armorer",
|
94 |
+
"armourers": "armorers",
|
95 |
+
"armouries": "armories",
|
96 |
+
"armoury": "armory",
|
97 |
+
"artefact": "artifact",
|
98 |
+
"artefacts": "artifacts",
|
99 |
+
"authorise": "authorize",
|
100 |
+
"authorised": "authorized",
|
101 |
+
"authorises": "authorizes",
|
102 |
+
"authorising": "authorizing",
|
103 |
+
"axe": "ax",
|
104 |
+
"backpedalled": "backpedaled",
|
105 |
+
"backpedalling": "backpedaling",
|
106 |
+
"bannister": "banister",
|
107 |
+
"bannisters": "banisters",
|
108 |
+
"baptise": "baptize",
|
109 |
+
"baptised": "baptized",
|
110 |
+
"baptises": "baptizes",
|
111 |
+
"baptising": "baptizing",
|
112 |
+
"bastardise": "bastardize",
|
113 |
+
"bastardised": "bastardized",
|
114 |
+
"bastardises": "bastardizes",
|
115 |
+
"bastardising": "bastardizing",
|
116 |
+
"battleax": "battleaxe",
|
117 |
+
"baulk": "balk",
|
118 |
+
"baulked": "balked",
|
119 |
+
"baulking": "balking",
|
120 |
+
"baulks": "balks",
|
121 |
+
"bedevilled": "bedeviled",
|
122 |
+
"bedevilling": "bedeviling",
|
123 |
+
"behaviour": "behavior",
|
124 |
+
"behavioural": "behavioral",
|
125 |
+
"behaviourism": "behaviorism",
|
126 |
+
"behaviourist": "behaviorist",
|
127 |
+
"behaviourists": "behaviorists",
|
128 |
+
"behaviours": "behaviors",
|
129 |
+
"behove": "behoove",
|
130 |
+
"behoved": "behooved",
|
131 |
+
"behoves": "behooves",
|
132 |
+
"bejewelled": "bejeweled",
|
133 |
+
"belabour": "belabor",
|
134 |
+
"belaboured": "belabored",
|
135 |
+
"belabouring": "belaboring",
|
136 |
+
"belabours": "belabors",
|
137 |
+
"bevelled": "beveled",
|
138 |
+
"bevvies": "bevies",
|
139 |
+
"bevvy": "bevy",
|
140 |
+
"biassed": "biased",
|
141 |
+
"biassing": "biasing",
|
142 |
+
"bingeing": "binging",
|
143 |
+
"bougainvillaea": "bougainvillea",
|
144 |
+
"bougainvillaeas": "bougainvilleas",
|
145 |
+
"bowdlerise": "bowdlerize",
|
146 |
+
"bowdlerised": "bowdlerized",
|
147 |
+
"bowdlerises": "bowdlerizes",
|
148 |
+
"bowdlerising": "bowdlerizing",
|
149 |
+
"breathalyse": "breathalyze",
|
150 |
+
"breathalysed": "breathalyzed",
|
151 |
+
"breathalyser": "breathalyzer",
|
152 |
+
"breathalysers": "breathalyzers",
|
153 |
+
"breathalyses": "breathalyzes",
|
154 |
+
"breathalysing": "breathalyzing",
|
155 |
+
"brutalise": "brutalize",
|
156 |
+
"brutalised": "brutalized",
|
157 |
+
"brutalises": "brutalizes",
|
158 |
+
"brutalising": "brutalizing",
|
159 |
+
"busses": "buses",
|
160 |
+
"bussing": "busing",
|
161 |
+
"caesarean": "cesarean",
|
162 |
+
"caesareans": "cesareans",
|
163 |
+
"calibre": "caliber",
|
164 |
+
"calibres": "calibers",
|
165 |
+
"calliper": "caliper",
|
166 |
+
"callipers": "calipers",
|
167 |
+
"callisthenics": "calisthenics",
|
168 |
+
"canalise": "canalize",
|
169 |
+
"canalised": "canalized",
|
170 |
+
"canalises": "canalizes",
|
171 |
+
"canalising": "canalizing",
|
172 |
+
"cancelation": "cancellation",
|
173 |
+
"cancelations": "cancellations",
|
174 |
+
"cancelled": "canceled",
|
175 |
+
"cancelling": "canceling",
|
176 |
+
"candour": "candor",
|
177 |
+
"cannibalise": "cannibalize",
|
178 |
+
"cannibalised": "cannibalized",
|
179 |
+
"cannibalises": "cannibalizes",
|
180 |
+
"cannibalising": "cannibalizing",
|
181 |
+
"canonise": "canonize",
|
182 |
+
"canonised": "canonized",
|
183 |
+
"canonises": "canonizes",
|
184 |
+
"canonising": "canonizing",
|
185 |
+
"capitalise": "capitalize",
|
186 |
+
"capitalised": "capitalized",
|
187 |
+
"capitalises": "capitalizes",
|
188 |
+
"capitalising": "capitalizing",
|
189 |
+
"caramelise": "caramelize",
|
190 |
+
"caramelised": "caramelized",
|
191 |
+
"caramelises": "caramelizes",
|
192 |
+
"caramelising": "caramelizing",
|
193 |
+
"carbonise": "carbonize",
|
194 |
+
"carbonised": "carbonized",
|
195 |
+
"carbonises": "carbonizes",
|
196 |
+
"carbonising": "carbonizing",
|
197 |
+
"carolled": "caroled",
|
198 |
+
"carolling": "caroling",
|
199 |
+
"catalogue": "catalog",
|
200 |
+
"catalogued": "cataloged",
|
201 |
+
"catalogues": "catalogs",
|
202 |
+
"cataloguing": "cataloging",
|
203 |
+
"catalyse": "catalyze",
|
204 |
+
"catalysed": "catalyzed",
|
205 |
+
"catalyses": "catalyzes",
|
206 |
+
"catalysing": "catalyzing",
|
207 |
+
"categorise": "categorize",
|
208 |
+
"categorised": "categorized",
|
209 |
+
"categorises": "categorizes",
|
210 |
+
"categorising": "categorizing",
|
211 |
+
"cauterise": "cauterize",
|
212 |
+
"cauterised": "cauterized",
|
213 |
+
"cauterises": "cauterizes",
|
214 |
+
"cauterising": "cauterizing",
|
215 |
+
"cavilled": "caviled",
|
216 |
+
"cavilling": "caviling",
|
217 |
+
"centigramme": "centigram",
|
218 |
+
"centigrammes": "centigrams",
|
219 |
+
"centilitre": "centiliter",
|
220 |
+
"centilitres": "centiliters",
|
221 |
+
"centimetre": "centimeter",
|
222 |
+
"centimetres": "centimeters",
|
223 |
+
"centralise": "centralize",
|
224 |
+
"centralised": "centralized",
|
225 |
+
"centralises": "centralizes",
|
226 |
+
"centralising": "centralizing",
|
227 |
+
"centre": "center",
|
228 |
+
"centred": "centered",
|
229 |
+
"centrefold": "centerfold",
|
230 |
+
"centrefolds": "centerfolds",
|
231 |
+
"centrepiece": "centerpiece",
|
232 |
+
"centrepieces": "centerpieces",
|
233 |
+
"centres": "centers",
|
234 |
+
"channelled": "channeled",
|
235 |
+
"channelling": "channeling",
|
236 |
+
"characterise": "characterize",
|
237 |
+
"characterised": "characterized",
|
238 |
+
"characterises": "characterizes",
|
239 |
+
"characterising": "characterizing",
|
240 |
+
"cheque": "check",
|
241 |
+
"chequebook": "checkbook",
|
242 |
+
"chequebooks": "checkbooks",
|
243 |
+
"chequered": "checkered",
|
244 |
+
"cheques": "checks",
|
245 |
+
"chilli": "chili",
|
246 |
+
"chimaera": "chimera",
|
247 |
+
"chimaeras": "chimeras",
|
248 |
+
"chiselled": "chiseled",
|
249 |
+
"chiselling": "chiseling",
|
250 |
+
"circularise": "circularize",
|
251 |
+
"circularised": "circularized",
|
252 |
+
"circularises": "circularizes",
|
253 |
+
"circularising": "circularizing",
|
254 |
+
"civilise": "civilize",
|
255 |
+
"civilised": "civilized",
|
256 |
+
"civilises": "civilizes",
|
257 |
+
"civilising": "civilizing",
|
258 |
+
"clamour": "clamor",
|
259 |
+
"clamoured": "clamored",
|
260 |
+
"clamouring": "clamoring",
|
261 |
+
"clamours": "clamors",
|
262 |
+
"clangour": "clangor",
|
263 |
+
"clarinettist": "clarinetist",
|
264 |
+
"clarinettists": "clarinetists",
|
265 |
+
"collectivise": "collectivize",
|
266 |
+
"collectivised": "collectivized",
|
267 |
+
"collectivises": "collectivizes",
|
268 |
+
"collectivising": "collectivizing",
|
269 |
+
"colonisation": "colonization",
|
270 |
+
"colonise": "colonize",
|
271 |
+
"colonised": "colonized",
|
272 |
+
"coloniser": "colonizer",
|
273 |
+
"colonisers": "colonizers",
|
274 |
+
"colonises": "colonizes",
|
275 |
+
"colonising": "colonizing",
|
276 |
+
"colour": "color",
|
277 |
+
"colourant": "colorant",
|
278 |
+
"colourants": "colorants",
|
279 |
+
"coloured": "colored",
|
280 |
+
"coloureds": "coloreds",
|
281 |
+
"colourful": "colorful",
|
282 |
+
"colourfully": "colorfully",
|
283 |
+
"colouring": "coloring",
|
284 |
+
"colourize": "colorize",
|
285 |
+
"colourized": "colorized",
|
286 |
+
"colourizes": "colorizes",
|
287 |
+
"colourizing": "colorizing",
|
288 |
+
"colourless": "colorless",
|
289 |
+
"colours": "colors",
|
290 |
+
"commercialise": "commercialize",
|
291 |
+
"commercialised": "commercialized",
|
292 |
+
"commercialises": "commercializes",
|
293 |
+
"commercialising": "commercializing",
|
294 |
+
"compartmentalise": "compartmentalize",
|
295 |
+
"compartmentalised": "compartmentalized",
|
296 |
+
"compartmentalises": "compartmentalizes",
|
297 |
+
"compartmentalising": "compartmentalizing",
|
298 |
+
"computerise": "computerize",
|
299 |
+
"computerised": "computerized",
|
300 |
+
"computerises": "computerizes",
|
301 |
+
"computerising": "computerizing",
|
302 |
+
"conceptualise": "conceptualize",
|
303 |
+
"conceptualised": "conceptualized",
|
304 |
+
"conceptualises": "conceptualizes",
|
305 |
+
"conceptualising": "conceptualizing",
|
306 |
+
"connexion": "connection",
|
307 |
+
"connexions": "connections",
|
308 |
+
"contextualise": "contextualize",
|
309 |
+
"contextualised": "contextualized",
|
310 |
+
"contextualises": "contextualizes",
|
311 |
+
"contextualising": "contextualizing",
|
312 |
+
"cosier": "cozier",
|
313 |
+
"cosies": "cozies",
|
314 |
+
"cosiest": "coziest",
|
315 |
+
"cosily": "cozily",
|
316 |
+
"cosiness": "coziness",
|
317 |
+
"cosy": "cozy",
|
318 |
+
"councillor": "councilor",
|
319 |
+
"councillors": "councilors",
|
320 |
+
"counselled": "counseled",
|
321 |
+
"counselling": "counseling",
|
322 |
+
"counsellor": "counselor",
|
323 |
+
"counsellors": "counselors",
|
324 |
+
"crenelated": "crenellated",
|
325 |
+
"criminalise": "criminalize",
|
326 |
+
"criminalised": "criminalized",
|
327 |
+
"criminalises": "criminalizes",
|
328 |
+
"criminalising": "criminalizing",
|
329 |
+
"criticise": "criticize",
|
330 |
+
"criticised": "criticized",
|
331 |
+
"criticises": "criticizes",
|
332 |
+
"criticising": "criticizing",
|
333 |
+
"crueller": "crueler",
|
334 |
+
"cruellest": "cruelest",
|
335 |
+
"crystallisation": "crystallization",
|
336 |
+
"crystallise": "crystallize",
|
337 |
+
"crystallised": "crystallized",
|
338 |
+
"crystallises": "crystallizes",
|
339 |
+
"crystallising": "crystallizing",
|
340 |
+
"cudgelled": "cudgeled",
|
341 |
+
"cudgelling": "cudgeling",
|
342 |
+
"customise": "customize",
|
343 |
+
"customised": "customized",
|
344 |
+
"customises": "customizes",
|
345 |
+
"customising": "customizing",
|
346 |
+
"cypher": "cipher",
|
347 |
+
"cyphers": "ciphers",
|
348 |
+
"decentralisation": "decentralization",
|
349 |
+
"decentralise": "decentralize",
|
350 |
+
"decentralised": "decentralized",
|
351 |
+
"decentralises": "decentralizes",
|
352 |
+
"decentralising": "decentralizing",
|
353 |
+
"decriminalisation": "decriminalization",
|
354 |
+
"decriminalise": "decriminalize",
|
355 |
+
"decriminalised": "decriminalized",
|
356 |
+
"decriminalises": "decriminalizes",
|
357 |
+
"decriminalising": "decriminalizing",
|
358 |
+
"defence": "defense",
|
359 |
+
"defenceless": "defenseless",
|
360 |
+
"defences": "defenses",
|
361 |
+
"dehumanisation": "dehumanization",
|
362 |
+
"dehumanise": "dehumanize",
|
363 |
+
"dehumanised": "dehumanized",
|
364 |
+
"dehumanises": "dehumanizes",
|
365 |
+
"dehumanising": "dehumanizing",
|
366 |
+
"demeanour": "demeanor",
|
367 |
+
"demilitarisation": "demilitarization",
|
368 |
+
"demilitarise": "demilitarize",
|
369 |
+
"demilitarised": "demilitarized",
|
370 |
+
"demilitarises": "demilitarizes",
|
371 |
+
"demilitarising": "demilitarizing",
|
372 |
+
"demobilisation": "demobilization",
|
373 |
+
"demobilise": "demobilize",
|
374 |
+
"demobilised": "demobilized",
|
375 |
+
"demobilises": "demobilizes",
|
376 |
+
"demobilising": "demobilizing",
|
377 |
+
"democratisation": "democratization",
|
378 |
+
"democratise": "democratize",
|
379 |
+
"democratised": "democratized",
|
380 |
+
"democratises": "democratizes",
|
381 |
+
"democratising": "democratizing",
|
382 |
+
"demonise": "demonize",
|
383 |
+
"demonised": "demonized",
|
384 |
+
"demonises": "demonizes",
|
385 |
+
"demonising": "demonizing",
|
386 |
+
"demoralisation": "demoralization",
|
387 |
+
"demoralise": "demoralize",
|
388 |
+
"demoralised": "demoralized",
|
389 |
+
"demoralises": "demoralizes",
|
390 |
+
"demoralising": "demoralizing",
|
391 |
+
"denationalisation": "denationalization",
|
392 |
+
"denationalise": "denationalize",
|
393 |
+
"denationalised": "denationalized",
|
394 |
+
"denationalises": "denationalizes",
|
395 |
+
"denationalising": "denationalizing",
|
396 |
+
"deodorise": "deodorize",
|
397 |
+
"deodorised": "deodorized",
|
398 |
+
"deodorises": "deodorizes",
|
399 |
+
"deodorising": "deodorizing",
|
400 |
+
"depersonalise": "depersonalize",
|
401 |
+
"depersonalised": "depersonalized",
|
402 |
+
"depersonalises": "depersonalizes",
|
403 |
+
"depersonalising": "depersonalizing",
|
404 |
+
"deputise": "deputize",
|
405 |
+
"deputised": "deputized",
|
406 |
+
"deputises": "deputizes",
|
407 |
+
"deputising": "deputizing",
|
408 |
+
"desensitisation": "desensitization",
|
409 |
+
"desensitise": "desensitize",
|
410 |
+
"desensitised": "desensitized",
|
411 |
+
"desensitises": "desensitizes",
|
412 |
+
"desensitising": "desensitizing",
|
413 |
+
"destabilisation": "destabilization",
|
414 |
+
"destabilise": "destabilize",
|
415 |
+
"destabilised": "destabilized",
|
416 |
+
"destabilises": "destabilizes",
|
417 |
+
"destabilising": "destabilizing",
|
418 |
+
"dialled": "dialed",
|
419 |
+
"dialling": "dialing",
|
420 |
+
"dialogue": "dialog",
|
421 |
+
"dialogues": "dialogs",
|
422 |
+
"diarrhoea": "diarrhea",
|
423 |
+
"digitise": "digitize",
|
424 |
+
"digitised": "digitized",
|
425 |
+
"digitises": "digitizes",
|
426 |
+
"digitising": "digitizing",
|
427 |
+
"disc": "disk",
|
428 |
+
"discolour": "discolor",
|
429 |
+
"discoloured": "discolored",
|
430 |
+
"discolouring": "discoloring",
|
431 |
+
"discolours": "discolors",
|
432 |
+
"discs": "disks",
|
433 |
+
"disembowelled": "disemboweled",
|
434 |
+
"disembowelling": "disemboweling",
|
435 |
+
"disfavour": "disfavor",
|
436 |
+
"dishevelled": "disheveled",
|
437 |
+
"dishonour": "dishonor",
|
438 |
+
"dishonourable": "dishonorable",
|
439 |
+
"dishonourably": "dishonorably",
|
440 |
+
"dishonoured": "dishonored",
|
441 |
+
"dishonouring": "dishonoring",
|
442 |
+
"dishonours": "dishonors",
|
443 |
+
"disorganisation": "disorganization",
|
444 |
+
"disorganised": "disorganized",
|
445 |
+
"distil": "distill",
|
446 |
+
"distils": "distills",
|
447 |
+
"dramatisation": "dramatization",
|
448 |
+
"dramatisations": "dramatizations",
|
449 |
+
"dramatise": "dramatize",
|
450 |
+
"dramatised": "dramatized",
|
451 |
+
"dramatises": "dramatizes",
|
452 |
+
"dramatising": "dramatizing",
|
453 |
+
"draught": "draft",
|
454 |
+
"draughtboard": "draftboard",
|
455 |
+
"draughtboards": "draftboards",
|
456 |
+
"draughtier": "draftier",
|
457 |
+
"draughtiest": "draftiest",
|
458 |
+
"draughts": "drafts",
|
459 |
+
"draughtsman": "draftsman",
|
460 |
+
"draughtsmanship": "draftsmanship",
|
461 |
+
"draughtsmen": "draftsmen",
|
462 |
+
"draughtswoman": "draftswoman",
|
463 |
+
"draughtswomen": "draftswomen",
|
464 |
+
"draughty": "drafty",
|
465 |
+
"drivelled": "driveled",
|
466 |
+
"drivelling": "driveling",
|
467 |
+
"duelled": "dueled",
|
468 |
+
"duelling": "dueling",
|
469 |
+
"economise": "economize",
|
470 |
+
"economised": "economized",
|
471 |
+
"economises": "economizes",
|
472 |
+
"economising": "economizing",
|
473 |
+
"edoema": "edema",
|
474 |
+
"editorialise": "editorialize",
|
475 |
+
"editorialised": "editorialized",
|
476 |
+
"editorialises": "editorializes",
|
477 |
+
"editorialising": "editorializing",
|
478 |
+
"empathise": "empathize",
|
479 |
+
"empathised": "empathized",
|
480 |
+
"empathises": "empathizes",
|
481 |
+
"empathising": "empathizing",
|
482 |
+
"emphasise": "emphasize",
|
483 |
+
"emphasised": "emphasized",
|
484 |
+
"emphasises": "emphasizes",
|
485 |
+
"emphasising": "emphasizing",
|
486 |
+
"enamelled": "enameled",
|
487 |
+
"enamelling": "enameling",
|
488 |
+
"enamoured": "enamored",
|
489 |
+
"encyclopaedia": "encyclopedia",
|
490 |
+
"encyclopaedias": "encyclopedias",
|
491 |
+
"encyclopaedic": "encyclopedic",
|
492 |
+
"endeavour": "endeavor",
|
493 |
+
"endeavoured": "endeavored",
|
494 |
+
"endeavouring": "endeavoring",
|
495 |
+
"endeavours": "endeavors",
|
496 |
+
"energise": "energize",
|
497 |
+
"energised": "energized",
|
498 |
+
"energises": "energizes",
|
499 |
+
"energising": "energizing",
|
500 |
+
"enrol": "enroll",
|
501 |
+
"enrols": "enrolls",
|
502 |
+
"enthral": "enthrall",
|
503 |
+
"enthrals": "enthralls",
|
504 |
+
"epaulette": "epaulet",
|
505 |
+
"epaulettes": "epaulets",
|
506 |
+
"epicentre": "epicenter",
|
507 |
+
"epicentres": "epicenters",
|
508 |
+
"epilogue": "epilog",
|
509 |
+
"epilogues": "epilogs",
|
510 |
+
"epitomise": "epitomize",
|
511 |
+
"epitomised": "epitomized",
|
512 |
+
"epitomises": "epitomizes",
|
513 |
+
"epitomising": "epitomizing",
|
514 |
+
"equalisation": "equalization",
|
515 |
+
"equalise": "equalize",
|
516 |
+
"equalised": "equalized",
|
517 |
+
"equaliser": "equalizer",
|
518 |
+
"equalisers": "equalizers",
|
519 |
+
"equalises": "equalizes",
|
520 |
+
"equalising": "equalizing",
|
521 |
+
"eulogise": "eulogize",
|
522 |
+
"eulogised": "eulogized",
|
523 |
+
"eulogises": "eulogizes",
|
524 |
+
"eulogising": "eulogizing",
|
525 |
+
"evangelise": "evangelize",
|
526 |
+
"evangelised": "evangelized",
|
527 |
+
"evangelises": "evangelizes",
|
528 |
+
"evangelising": "evangelizing",
|
529 |
+
"exorcise": "exorcize",
|
530 |
+
"exorcised": "exorcized",
|
531 |
+
"exorcises": "exorcizes",
|
532 |
+
"exorcising": "exorcizing",
|
533 |
+
"extemporisation": "extemporization",
|
534 |
+
"extemporise": "extemporize",
|
535 |
+
"extemporised": "extemporized",
|
536 |
+
"extemporises": "extemporizes",
|
537 |
+
"extemporising": "extemporizing",
|
538 |
+
"externalisation": "externalization",
|
539 |
+
"externalisations": "externalizations",
|
540 |
+
"externalise": "externalize",
|
541 |
+
"externalised": "externalized",
|
542 |
+
"externalises": "externalizes",
|
543 |
+
"externalising": "externalizing",
|
544 |
+
"factorise": "factorize",
|
545 |
+
"factorised": "factorized",
|
546 |
+
"factorises": "factorizes",
|
547 |
+
"factorising": "factorizing",
|
548 |
+
"faecal": "fecal",
|
549 |
+
"faeces": "feces",
|
550 |
+
"familiarisation": "familiarization",
|
551 |
+
"familiarise": "familiarize",
|
552 |
+
"familiarised": "familiarized",
|
553 |
+
"familiarises": "familiarizes",
|
554 |
+
"familiarising": "familiarizing",
|
555 |
+
"fantasise": "fantasize",
|
556 |
+
"fantasised": "fantasized",
|
557 |
+
"fantasises": "fantasizes",
|
558 |
+
"fantasising": "fantasizing",
|
559 |
+
"favour": "favor",
|
560 |
+
"favourable": "favorable",
|
561 |
+
"favourably": "favorably",
|
562 |
+
"favoured": "favored",
|
563 |
+
"favouring": "favoring",
|
564 |
+
"favourite": "favorite",
|
565 |
+
"favourites": "favorites",
|
566 |
+
"favouritism": "favoritism",
|
567 |
+
"favours": "favors",
|
568 |
+
"feminise": "feminize",
|
569 |
+
"feminised": "feminized",
|
570 |
+
"feminises": "feminizes",
|
571 |
+
"feminising": "feminizing",
|
572 |
+
"fertilisation": "fertilization",
|
573 |
+
"fertilise": "fertilize",
|
574 |
+
"fertilised": "fertilized",
|
575 |
+
"fertiliser": "fertilizer",
|
576 |
+
"fertilisers": "fertilizers",
|
577 |
+
"fertilises": "fertilizes",
|
578 |
+
"fertilising": "fertilizing",
|
579 |
+
"fervour": "fervor",
|
580 |
+
"fibre": "fiber",
|
581 |
+
"fibreglass": "fiberglass",
|
582 |
+
"fibres": "fibers",
|
583 |
+
"fictionalisation": "fictionalization",
|
584 |
+
"fictionalisations": "fictionalizations",
|
585 |
+
"fictionalise": "fictionalize",
|
586 |
+
"fictionalised": "fictionalized",
|
587 |
+
"fictionalises": "fictionalizes",
|
588 |
+
"fictionalising": "fictionalizing",
|
589 |
+
"fillet": "filet",
|
590 |
+
"filleted": "fileted",
|
591 |
+
"filleting": "fileting",
|
592 |
+
"fillets": "filets",
|
593 |
+
"finalisation": "finalization",
|
594 |
+
"finalise": "finalize",
|
595 |
+
"finalised": "finalized",
|
596 |
+
"finalises": "finalizes",
|
597 |
+
"finalising": "finalizing",
|
598 |
+
"flautist": "flutist",
|
599 |
+
"flautists": "flutists",
|
600 |
+
"flavour": "flavor",
|
601 |
+
"flavoured": "flavored",
|
602 |
+
"flavouring": "flavoring",
|
603 |
+
"flavourings": "flavorings",
|
604 |
+
"flavourless": "flavorless",
|
605 |
+
"flavours": "flavors",
|
606 |
+
"flavoursome": "flavorsome",
|
607 |
+
"flyer / flier": "flier / flyer",
|
608 |
+
"foetal": "fetal",
|
609 |
+
"foetid": "fetid",
|
610 |
+
"foetus": "fetus",
|
611 |
+
"foetuses": "fetuses",
|
612 |
+
"formalisation": "formalization",
|
613 |
+
"formalise": "formalize",
|
614 |
+
"formalised": "formalized",
|
615 |
+
"formalises": "formalizes",
|
616 |
+
"formalising": "formalizing",
|
617 |
+
"fossilisation": "fossilization",
|
618 |
+
"fossilise": "fossilize",
|
619 |
+
"fossilised": "fossilized",
|
620 |
+
"fossilises": "fossilizes",
|
621 |
+
"fossilising": "fossilizing",
|
622 |
+
"fraternisation": "fraternization",
|
623 |
+
"fraternise": "fraternize",
|
624 |
+
"fraternised": "fraternized",
|
625 |
+
"fraternises": "fraternizes",
|
626 |
+
"fraternising": "fraternizing",
|
627 |
+
"fulfil": "fulfill",
|
628 |
+
"fulfilment": "fulfillment",
|
629 |
+
"fulfils": "fulfills",
|
630 |
+
"funnelled": "funneled",
|
631 |
+
"funnelling": "funneling",
|
632 |
+
"galvanise": "galvanize",
|
633 |
+
"galvanised": "galvanized",
|
634 |
+
"galvanises": "galvanizes",
|
635 |
+
"galvanising": "galvanizing",
|
636 |
+
"gambolled": "gamboled",
|
637 |
+
"gambolling": "gamboling",
|
638 |
+
"gaol": "jail",
|
639 |
+
"gaolbird": "jailbird",
|
640 |
+
"gaolbirds": "jailbirds",
|
641 |
+
"gaolbreak": "jailbreak",
|
642 |
+
"gaolbreaks": "jailbreaks",
|
643 |
+
"gaoled": "jailed",
|
644 |
+
"gaoler": "jailer",
|
645 |
+
"gaolers": "jailers",
|
646 |
+
"gaoling": "jailing",
|
647 |
+
"gaols": "jails",
|
648 |
+
"gasses": "gases",
|
649 |
+
"gage": "gauge",
|
650 |
+
"gaged": "gauged",
|
651 |
+
"gages": "gauges",
|
652 |
+
"gaging": "gauging",
|
653 |
+
"generalisation": "generalization",
|
654 |
+
"generalisations": "generalizations",
|
655 |
+
"generalise": "generalize",
|
656 |
+
"generalised": "generalized",
|
657 |
+
"generalises": "generalizes",
|
658 |
+
"generalising": "generalizing",
|
659 |
+
"ghettoise": "ghettoize",
|
660 |
+
"ghettoised": "ghettoized",
|
661 |
+
"ghettoises": "ghettoizes",
|
662 |
+
"ghettoising": "ghettoizing",
|
663 |
+
"gipsies": "gypsies",
|
664 |
+
"glamorise": "glamorize",
|
665 |
+
"glamorised": "glamorized",
|
666 |
+
"glamorises": "glamorizes",
|
667 |
+
"glamorising": "glamorizing",
|
668 |
+
"glamor": "glamour",
|
669 |
+
"globalisation": "globalization",
|
670 |
+
"globalise": "globalize",
|
671 |
+
"globalised": "globalized",
|
672 |
+
"globalises": "globalizes",
|
673 |
+
"globalising": "globalizing",
|
674 |
+
"glueing": "gluing",
|
675 |
+
"goitre": "goiter",
|
676 |
+
"goitres": "goiters",
|
677 |
+
"gonorrhoea": "gonorrhea",
|
678 |
+
"gramme": "gram",
|
679 |
+
"grammes": "grams",
|
680 |
+
"gravelled": "graveled",
|
681 |
+
"grey": "gray",
|
682 |
+
"greyed": "grayed",
|
683 |
+
"greying": "graying",
|
684 |
+
"greyish": "grayish",
|
685 |
+
"greyness": "grayness",
|
686 |
+
"greys": "grays",
|
687 |
+
"grovelled": "groveled",
|
688 |
+
"grovelling": "groveling",
|
689 |
+
"groyne": "groin",
|
690 |
+
"groynes": "groins",
|
691 |
+
"gruelling": "grueling",
|
692 |
+
"gruellingly": "gruelingly",
|
693 |
+
"gryphon": "griffin",
|
694 |
+
"gryphons": "griffins",
|
695 |
+
"gynaecological": "gynecological",
|
696 |
+
"gynaecologist": "gynecologist",
|
697 |
+
"gynaecologists": "gynecologists",
|
698 |
+
"gynaecology": "gynecology",
|
699 |
+
"haematological": "hematological",
|
700 |
+
"haematologist": "hematologist",
|
701 |
+
"haematologists": "hematologists",
|
702 |
+
"haematology": "hematology",
|
703 |
+
"haemoglobin": "hemoglobin",
|
704 |
+
"haemophilia": "hemophilia",
|
705 |
+
"haemophiliac": "hemophiliac",
|
706 |
+
"haemophiliacs": "hemophiliacs",
|
707 |
+
"haemorrhage": "hemorrhage",
|
708 |
+
"haemorrhaged": "hemorrhaged",
|
709 |
+
"haemorrhages": "hemorrhages",
|
710 |
+
"haemorrhaging": "hemorrhaging",
|
711 |
+
"haemorrhoids": "hemorrhoids",
|
712 |
+
"harbour": "harbor",
|
713 |
+
"harboured": "harbored",
|
714 |
+
"harbouring": "harboring",
|
715 |
+
"harbours": "harbors",
|
716 |
+
"harmonisation": "harmonization",
|
717 |
+
"harmonise": "harmonize",
|
718 |
+
"harmonised": "harmonized",
|
719 |
+
"harmonises": "harmonizes",
|
720 |
+
"harmonising": "harmonizing",
|
721 |
+
"homoeopath": "homeopath",
|
722 |
+
"homoeopathic": "homeopathic",
|
723 |
+
"homoeopaths": "homeopaths",
|
724 |
+
"homoeopathy": "homeopathy",
|
725 |
+
"homogenise": "homogenize",
|
726 |
+
"homogenised": "homogenized",
|
727 |
+
"homogenises": "homogenizes",
|
728 |
+
"homogenising": "homogenizing",
|
729 |
+
"honour": "honor",
|
730 |
+
"honourable": "honorable",
|
731 |
+
"honourably": "honorably",
|
732 |
+
"honoured": "honored",
|
733 |
+
"honouring": "honoring",
|
734 |
+
"honours": "honors",
|
735 |
+
"hospitalisation": "hospitalization",
|
736 |
+
"hospitalise": "hospitalize",
|
737 |
+
"hospitalised": "hospitalized",
|
738 |
+
"hospitalises": "hospitalizes",
|
739 |
+
"hospitalising": "hospitalizing",
|
740 |
+
"humanise": "humanize",
|
741 |
+
"humanised": "humanized",
|
742 |
+
"humanises": "humanizes",
|
743 |
+
"humanising": "humanizing",
|
744 |
+
"humour": "humor",
|
745 |
+
"humoured": "humored",
|
746 |
+
"humouring": "humoring",
|
747 |
+
"humourless": "humorless",
|
748 |
+
"humours": "humors",
|
749 |
+
"hybridise": "hybridize",
|
750 |
+
"hybridised": "hybridized",
|
751 |
+
"hybridises": "hybridizes",
|
752 |
+
"hybridising": "hybridizing",
|
753 |
+
"hypnotise": "hypnotize",
|
754 |
+
"hypnotised": "hypnotized",
|
755 |
+
"hypnotises": "hypnotizes",
|
756 |
+
"hypnotising": "hypnotizing",
|
757 |
+
"hypothesise": "hypothesize",
|
758 |
+
"hypothesised": "hypothesized",
|
759 |
+
"hypothesises": "hypothesizes",
|
760 |
+
"hypothesising": "hypothesizing",
|
761 |
+
"idealisation": "idealization",
|
762 |
+
"idealise": "idealize",
|
763 |
+
"idealised": "idealized",
|
764 |
+
"idealises": "idealizes",
|
765 |
+
"idealising": "idealizing",
|
766 |
+
"idolise": "idolize",
|
767 |
+
"idolised": "idolized",
|
768 |
+
"idolises": "idolizes",
|
769 |
+
"idolising": "idolizing",
|
770 |
+
"immobilisation": "immobilization",
|
771 |
+
"immobilise": "immobilize",
|
772 |
+
"immobilised": "immobilized",
|
773 |
+
"immobiliser": "immobilizer",
|
774 |
+
"immobilisers": "immobilizers",
|
775 |
+
"immobilises": "immobilizes",
|
776 |
+
"immobilising": "immobilizing",
|
777 |
+
"immortalise": "immortalize",
|
778 |
+
"immortalised": "immortalized",
|
779 |
+
"immortalises": "immortalizes",
|
780 |
+
"immortalising": "immortalizing",
|
781 |
+
"immunisation": "immunization",
|
782 |
+
"immunise": "immunize",
|
783 |
+
"immunised": "immunized",
|
784 |
+
"immunises": "immunizes",
|
785 |
+
"immunising": "immunizing",
|
786 |
+
"impanelled": "impaneled",
|
787 |
+
"impanelling": "impaneling",
|
788 |
+
"imperilled": "imperiled",
|
789 |
+
"imperilling": "imperiling",
|
790 |
+
"individualise": "individualize",
|
791 |
+
"individualised": "individualized",
|
792 |
+
"individualises": "individualizes",
|
793 |
+
"individualising": "individualizing",
|
794 |
+
"industrialise": "industrialize",
|
795 |
+
"industrialised": "industrialized",
|
796 |
+
"industrialises": "industrializes",
|
797 |
+
"industrialising": "industrializing",
|
798 |
+
"inflexion": "inflection",
|
799 |
+
"inflexions": "inflections",
|
800 |
+
"initialise": "initialize",
|
801 |
+
"initialised": "initialized",
|
802 |
+
"initialises": "initializes",
|
803 |
+
"initialising": "initializing",
|
804 |
+
"initialled": "initialed",
|
805 |
+
"initialling": "initialing",
|
806 |
+
"instal": "install",
|
807 |
+
"instalment": "installment",
|
808 |
+
"instalments": "installments",
|
809 |
+
"instals": "installs",
|
810 |
+
"instil": "instill",
|
811 |
+
"instils": "instills",
|
812 |
+
"institutionalisation": "institutionalization",
|
813 |
+
"institutionalise": "institutionalize",
|
814 |
+
"institutionalised": "institutionalized",
|
815 |
+
"institutionalises": "institutionalizes",
|
816 |
+
"institutionalising": "institutionalizing",
|
817 |
+
"intellectualise": "intellectualize",
|
818 |
+
"intellectualised": "intellectualized",
|
819 |
+
"intellectualises": "intellectualizes",
|
820 |
+
"intellectualising": "intellectualizing",
|
821 |
+
"internalisation": "internalization",
|
822 |
+
"internalise": "internalize",
|
823 |
+
"internalised": "internalized",
|
824 |
+
"internalises": "internalizes",
|
825 |
+
"internalising": "internalizing",
|
826 |
+
"internationalisation": "internationalization",
|
827 |
+
"internationalise": "internationalize",
|
828 |
+
"internationalised": "internationalized",
|
829 |
+
"internationalises": "internationalizes",
|
830 |
+
"internationalising": "internationalizing",
|
831 |
+
"ionisation": "ionization",
|
832 |
+
"ionise": "ionize",
|
833 |
+
"ionised": "ionized",
|
834 |
+
"ioniser": "ionizer",
|
835 |
+
"ionisers": "ionizers",
|
836 |
+
"ionises": "ionizes",
|
837 |
+
"ionising": "ionizing",
|
838 |
+
"italicise": "italicize",
|
839 |
+
"italicised": "italicized",
|
840 |
+
"italicises": "italicizes",
|
841 |
+
"italicising": "italicizing",
|
842 |
+
"itemise": "itemize",
|
843 |
+
"itemised": "itemized",
|
844 |
+
"itemises": "itemizes",
|
845 |
+
"itemising": "itemizing",
|
846 |
+
"jeopardise": "jeopardize",
|
847 |
+
"jeopardised": "jeopardized",
|
848 |
+
"jeopardises": "jeopardizes",
|
849 |
+
"jeopardising": "jeopardizing",
|
850 |
+
"jewelled": "jeweled",
|
851 |
+
"jeweller": "jeweler",
|
852 |
+
"jewellers": "jewelers",
|
853 |
+
"jewellery": "jewelry",
|
854 |
+
"judgement": "judgment",
|
855 |
+
"kilogramme": "kilogram",
|
856 |
+
"kilogrammes": "kilograms",
|
857 |
+
"kilometre": "kilometer",
|
858 |
+
"kilometres": "kilometers",
|
859 |
+
"labelled": "labeled",
|
860 |
+
"labelling": "labeling",
|
861 |
+
"labour": "labor",
|
862 |
+
"laboured": "labored",
|
863 |
+
"labourer": "laborer",
|
864 |
+
"labourers": "laborers",
|
865 |
+
"labouring": "laboring",
|
866 |
+
"labours": "labors",
|
867 |
+
"lacklustre": "lackluster",
|
868 |
+
"legalisation": "legalization",
|
869 |
+
"legalise": "legalize",
|
870 |
+
"legalised": "legalized",
|
871 |
+
"legalises": "legalizes",
|
872 |
+
"legalising": "legalizing",
|
873 |
+
"legitimise": "legitimize",
|
874 |
+
"legitimised": "legitimized",
|
875 |
+
"legitimises": "legitimizes",
|
876 |
+
"legitimising": "legitimizing",
|
877 |
+
"leukaemia": "leukemia",
|
878 |
+
"levelled": "leveled",
|
879 |
+
"leveller": "leveler",
|
880 |
+
"levellers": "levelers",
|
881 |
+
"levelling": "leveling",
|
882 |
+
"libelled": "libeled",
|
883 |
+
"libelling": "libeling",
|
884 |
+
"libellous": "libelous",
|
885 |
+
"liberalisation": "liberalization",
|
886 |
+
"liberalise": "liberalize",
|
887 |
+
"liberalised": "liberalized",
|
888 |
+
"liberalises": "liberalizes",
|
889 |
+
"liberalising": "liberalizing",
|
890 |
+
"licence": "license",
|
891 |
+
"licenced": "licensed",
|
892 |
+
"licences": "licenses",
|
893 |
+
"licencing": "licensing",
|
894 |
+
"likeable": "likable",
|
895 |
+
"lionisation": "lionization",
|
896 |
+
"lionise": "lionize",
|
897 |
+
"lionised": "lionized",
|
898 |
+
"lionises": "lionizes",
|
899 |
+
"lionising": "lionizing",
|
900 |
+
"liquidise": "liquidize",
|
901 |
+
"liquidised": "liquidized",
|
902 |
+
"liquidiser": "liquidizer",
|
903 |
+
"liquidisers": "liquidizers",
|
904 |
+
"liquidises": "liquidizes",
|
905 |
+
"liquidising": "liquidizing",
|
906 |
+
"litre": "liter",
|
907 |
+
"litres": "liters",
|
908 |
+
"localise": "localize",
|
909 |
+
"localised": "localized",
|
910 |
+
"localises": "localizes",
|
911 |
+
"localising": "localizing",
|
912 |
+
"louvre": "louver",
|
913 |
+
"louvred": "louvered",
|
914 |
+
"louvres": "louvers",
|
915 |
+
"lustre": "luster",
|
916 |
+
"magnetise": "magnetize",
|
917 |
+
"magnetised": "magnetized",
|
918 |
+
"magnetises": "magnetizes",
|
919 |
+
"magnetising": "magnetizing",
|
920 |
+
"manoeuvrability": "maneuverability",
|
921 |
+
"manoeuvrable": "maneuverable",
|
922 |
+
"manoeuvre": "maneuver",
|
923 |
+
"manoeuvred": "maneuvered",
|
924 |
+
"manoeuvres": "maneuvers",
|
925 |
+
"manoeuvring": "maneuvering",
|
926 |
+
"manoeuvrings": "maneuverings",
|
927 |
+
"marginalisation": "marginalization",
|
928 |
+
"marginalise": "marginalize",
|
929 |
+
"marginalised": "marginalized",
|
930 |
+
"marginalises": "marginalizes",
|
931 |
+
"marginalising": "marginalizing",
|
932 |
+
"marshalled": "marshaled",
|
933 |
+
"marshalling": "marshaling",
|
934 |
+
"marvelled": "marveled",
|
935 |
+
"marvelling": "marveling",
|
936 |
+
"marvellous": "marvelous",
|
937 |
+
"marvellously": "marvelously",
|
938 |
+
"materialisation": "materialization",
|
939 |
+
"materialise": "materialize",
|
940 |
+
"materialised": "materialized",
|
941 |
+
"materialises": "materializes",
|
942 |
+
"materialising": "materializing",
|
943 |
+
"maximisation": "maximization",
|
944 |
+
"maximise": "maximize",
|
945 |
+
"maximised": "maximized",
|
946 |
+
"maximises": "maximizes",
|
947 |
+
"maximising": "maximizing",
|
948 |
+
"meagre": "meager",
|
949 |
+
"mechanisation": "mechanization",
|
950 |
+
"mechanise": "mechanize",
|
951 |
+
"mechanised": "mechanized",
|
952 |
+
"mechanises": "mechanizes",
|
953 |
+
"mechanising": "mechanizing",
|
954 |
+
"mediaeval": "medieval",
|
955 |
+
"memorialise": "memorialize",
|
956 |
+
"memorialised": "memorialized",
|
957 |
+
"memorialises": "memorializes",
|
958 |
+
"memorialising": "memorializing",
|
959 |
+
"memorise": "memorize",
|
960 |
+
"memorised": "memorized",
|
961 |
+
"memorises": "memorizes",
|
962 |
+
"memorising": "memorizing",
|
963 |
+
"mesmerise": "mesmerize",
|
964 |
+
"mesmerised": "mesmerized",
|
965 |
+
"mesmerises": "mesmerizes",
|
966 |
+
"mesmerising": "mesmerizing",
|
967 |
+
"metabolise": "metabolize",
|
968 |
+
"metabolised": "metabolized",
|
969 |
+
"metabolises": "metabolizes",
|
970 |
+
"metabolising": "metabolizing",
|
971 |
+
"metre": "meter",
|
972 |
+
"metres": "meters",
|
973 |
+
"micrometre": "micrometer",
|
974 |
+
"micrometres": "micrometers",
|
975 |
+
"militarise": "militarize",
|
976 |
+
"militarised": "militarized",
|
977 |
+
"militarises": "militarizes",
|
978 |
+
"militarising": "militarizing",
|
979 |
+
"milligramme": "milligram",
|
980 |
+
"milligrammes": "milligrams",
|
981 |
+
"millilitre": "milliliter",
|
982 |
+
"millilitres": "milliliters",
|
983 |
+
"millimetre": "millimeter",
|
984 |
+
"millimetres": "millimeters",
|
985 |
+
"miniaturisation": "miniaturization",
|
986 |
+
"miniaturise": "miniaturize",
|
987 |
+
"miniaturised": "miniaturized",
|
988 |
+
"miniaturises": "miniaturizes",
|
989 |
+
"miniaturising": "miniaturizing",
|
990 |
+
"minibusses": "minibuses",
|
991 |
+
"minimise": "minimize",
|
992 |
+
"minimised": "minimized",
|
993 |
+
"minimises": "minimizes",
|
994 |
+
"minimising": "minimizing",
|
995 |
+
"misbehaviour": "misbehavior",
|
996 |
+
"misdemeanour": "misdemeanor",
|
997 |
+
"misdemeanours": "misdemeanors",
|
998 |
+
"misspelt": "misspelled",
|
999 |
+
"mitre": "miter",
|
1000 |
+
"mitres": "miters",
|
1001 |
+
"mobilisation": "mobilization",
|
1002 |
+
"mobilise": "mobilize",
|
1003 |
+
"mobilised": "mobilized",
|
1004 |
+
"mobilises": "mobilizes",
|
1005 |
+
"mobilising": "mobilizing",
|
1006 |
+
"modelled": "modeled",
|
1007 |
+
"modeller": "modeler",
|
1008 |
+
"modellers": "modelers",
|
1009 |
+
"modelling": "modeling",
|
1010 |
+
"modernise": "modernize",
|
1011 |
+
"modernised": "modernized",
|
1012 |
+
"modernises": "modernizes",
|
1013 |
+
"modernising": "modernizing",
|
1014 |
+
"moisturise": "moisturize",
|
1015 |
+
"moisturised": "moisturized",
|
1016 |
+
"moisturiser": "moisturizer",
|
1017 |
+
"moisturisers": "moisturizers",
|
1018 |
+
"moisturises": "moisturizes",
|
1019 |
+
"moisturising": "moisturizing",
|
1020 |
+
"monologue": "monolog",
|
1021 |
+
"monologues": "monologs",
|
1022 |
+
"monopolisation": "monopolization",
|
1023 |
+
"monopolise": "monopolize",
|
1024 |
+
"monopolised": "monopolized",
|
1025 |
+
"monopolises": "monopolizes",
|
1026 |
+
"monopolising": "monopolizing",
|
1027 |
+
"moralise": "moralize",
|
1028 |
+
"moralised": "moralized",
|
1029 |
+
"moralises": "moralizes",
|
1030 |
+
"moralising": "moralizing",
|
1031 |
+
"motorised": "motorized",
|
1032 |
+
"mould": "mold",
|
1033 |
+
"moulded": "molded",
|
1034 |
+
"moulder": "molder",
|
1035 |
+
"mouldered": "moldered",
|
1036 |
+
"mouldering": "moldering",
|
1037 |
+
"moulders": "molders",
|
1038 |
+
"mouldier": "moldier",
|
1039 |
+
"mouldiest": "moldiest",
|
1040 |
+
"moulding": "molding",
|
1041 |
+
"mouldings": "moldings",
|
1042 |
+
"moulds": "molds",
|
1043 |
+
"mouldy": "moldy",
|
1044 |
+
"moult": "molt",
|
1045 |
+
"moulted": "molted",
|
1046 |
+
"moulting": "molting",
|
1047 |
+
"moults": "molts",
|
1048 |
+
"moustache": "mustache",
|
1049 |
+
"moustached": "mustached",
|
1050 |
+
"moustaches": "mustaches",
|
1051 |
+
"moustachioed": "mustachioed",
|
1052 |
+
"multicoloured": "multicolored",
|
1053 |
+
"nationalisation": "nationalization",
|
1054 |
+
"nationalisations": "nationalizations",
|
1055 |
+
"nationalise": "nationalize",
|
1056 |
+
"nationalised": "nationalized",
|
1057 |
+
"nationalises": "nationalizes",
|
1058 |
+
"nationalising": "nationalizing",
|
1059 |
+
"naturalisation": "naturalization",
|
1060 |
+
"naturalise": "naturalize",
|
1061 |
+
"naturalised": "naturalized",
|
1062 |
+
"naturalises": "naturalizes",
|
1063 |
+
"naturalising": "naturalizing",
|
1064 |
+
"neighbour": "neighbor",
|
1065 |
+
"neighbourhood": "neighborhood",
|
1066 |
+
"neighbourhoods": "neighborhoods",
|
1067 |
+
"neighbouring": "neighboring",
|
1068 |
+
"neighbourliness": "neighborliness",
|
1069 |
+
"neighbourly": "neighborly",
|
1070 |
+
"neighbours": "neighbors",
|
1071 |
+
"neutralisation": "neutralization",
|
1072 |
+
"neutralise": "neutralize",
|
1073 |
+
"neutralised": "neutralized",
|
1074 |
+
"neutralises": "neutralizes",
|
1075 |
+
"neutralising": "neutralizing",
|
1076 |
+
"normalisation": "normalization",
|
1077 |
+
"normalise": "normalize",
|
1078 |
+
"normalised": "normalized",
|
1079 |
+
"normalises": "normalizes",
|
1080 |
+
"normalising": "normalizing",
|
1081 |
+
"odour": "odor",
|
1082 |
+
"odourless": "odorless",
|
1083 |
+
"odours": "odors",
|
1084 |
+
"oesophagus": "esophagus",
|
1085 |
+
"oesophaguses": "esophaguses",
|
1086 |
+
"oestrogen": "estrogen",
|
1087 |
+
"offence": "offense",
|
1088 |
+
"offences": "offenses",
|
1089 |
+
"omelette": "omelet",
|
1090 |
+
"omelettes": "omelets",
|
1091 |
+
"optimise": "optimize",
|
1092 |
+
"optimised": "optimized",
|
1093 |
+
"optimises": "optimizes",
|
1094 |
+
"optimising": "optimizing",
|
1095 |
+
"organisation": "organization",
|
1096 |
+
"organisational": "organizational",
|
1097 |
+
"organisations": "organizations",
|
1098 |
+
"organise": "organize",
|
1099 |
+
"organised": "organized",
|
1100 |
+
"organiser": "organizer",
|
1101 |
+
"organisers": "organizers",
|
1102 |
+
"organises": "organizes",
|
1103 |
+
"organising": "organizing",
|
1104 |
+
"orthopaedic": "orthopedic",
|
1105 |
+
"orthopaedics": "orthopedics",
|
1106 |
+
"ostracise": "ostracize",
|
1107 |
+
"ostracised": "ostracized",
|
1108 |
+
"ostracises": "ostracizes",
|
1109 |
+
"ostracising": "ostracizing",
|
1110 |
+
"outmanoeuvre": "outmaneuver",
|
1111 |
+
"outmanoeuvred": "outmaneuvered",
|
1112 |
+
"outmanoeuvres": "outmaneuvers",
|
1113 |
+
"outmanoeuvring": "outmaneuvering",
|
1114 |
+
"overemphasise": "overemphasize",
|
1115 |
+
"overemphasised": "overemphasized",
|
1116 |
+
"overemphasises": "overemphasizes",
|
1117 |
+
"overemphasising": "overemphasizing",
|
1118 |
+
"oxidisation": "oxidization",
|
1119 |
+
"oxidise": "oxidize",
|
1120 |
+
"oxidised": "oxidized",
|
1121 |
+
"oxidises": "oxidizes",
|
1122 |
+
"oxidising": "oxidizing",
|
1123 |
+
"paederast": "pederast",
|
1124 |
+
"paederasts": "pederasts",
|
1125 |
+
"paediatric": "pediatric",
|
1126 |
+
"paediatrician": "pediatrician",
|
1127 |
+
"paediatricians": "pediatricians",
|
1128 |
+
"paediatrics": "pediatrics",
|
1129 |
+
"paedophile": "pedophile",
|
1130 |
+
"paedophiles": "pedophiles",
|
1131 |
+
"paedophilia": "pedophilia",
|
1132 |
+
"palaeolithic": "paleolithic",
|
1133 |
+
"palaeontologist": "paleontologist",
|
1134 |
+
"palaeontologists": "paleontologists",
|
1135 |
+
"palaeontology": "paleontology",
|
1136 |
+
"panelled": "paneled",
|
1137 |
+
"panelling": "paneling",
|
1138 |
+
"panellist": "panelist",
|
1139 |
+
"panellists": "panelists",
|
1140 |
+
"paralyse": "paralyze",
|
1141 |
+
"paralysed": "paralyzed",
|
1142 |
+
"paralyses": "paralyzes",
|
1143 |
+
"paralysing": "paralyzing",
|
1144 |
+
"parcelled": "parceled",
|
1145 |
+
"parcelling": "parceling",
|
1146 |
+
"parlour": "parlor",
|
1147 |
+
"parlours": "parlors",
|
1148 |
+
"particularise": "particularize",
|
1149 |
+
"particularised": "particularized",
|
1150 |
+
"particularises": "particularizes",
|
1151 |
+
"particularising": "particularizing",
|
1152 |
+
"passivisation": "passivization",
|
1153 |
+
"passivise": "passivize",
|
1154 |
+
"passivised": "passivized",
|
1155 |
+
"passivises": "passivizes",
|
1156 |
+
"passivising": "passivizing",
|
1157 |
+
"pasteurisation": "pasteurization",
|
1158 |
+
"pasteurise": "pasteurize",
|
1159 |
+
"pasteurised": "pasteurized",
|
1160 |
+
"pasteurises": "pasteurizes",
|
1161 |
+
"pasteurising": "pasteurizing",
|
1162 |
+
"patronise": "patronize",
|
1163 |
+
"patronised": "patronized",
|
1164 |
+
"patronises": "patronizes",
|
1165 |
+
"patronising": "patronizing",
|
1166 |
+
"patronisingly": "patronizingly",
|
1167 |
+
"pedalled": "pedaled",
|
1168 |
+
"pedalling": "pedaling",
|
1169 |
+
"pedestrianisation": "pedestrianization",
|
1170 |
+
"pedestrianise": "pedestrianize",
|
1171 |
+
"pedestrianised": "pedestrianized",
|
1172 |
+
"pedestrianises": "pedestrianizes",
|
1173 |
+
"pedestrianising": "pedestrianizing",
|
1174 |
+
"penalise": "penalize",
|
1175 |
+
"penalised": "penalized",
|
1176 |
+
"penalises": "penalizes",
|
1177 |
+
"penalising": "penalizing",
|
1178 |
+
"pencilled": "penciled",
|
1179 |
+
"pencilling": "penciling",
|
1180 |
+
"personalise": "personalize",
|
1181 |
+
"personalised": "personalized",
|
1182 |
+
"personalises": "personalizes",
|
1183 |
+
"personalising": "personalizing",
|
1184 |
+
"pharmacopoeia": "pharmacopeia",
|
1185 |
+
"pharmacopoeias": "pharmacopeias",
|
1186 |
+
"philosophise": "philosophize",
|
1187 |
+
"philosophised": "philosophized",
|
1188 |
+
"philosophises": "philosophizes",
|
1189 |
+
"philosophising": "philosophizing",
|
1190 |
+
"philtre": "filter",
|
1191 |
+
"philtres": "filters",
|
1192 |
+
"phoney": "phony",
|
1193 |
+
"plagiarise": "plagiarize",
|
1194 |
+
"plagiarised": "plagiarized",
|
1195 |
+
"plagiarises": "plagiarizes",
|
1196 |
+
"plagiarising": "plagiarizing",
|
1197 |
+
"plough": "plow",
|
1198 |
+
"ploughed": "plowed",
|
1199 |
+
"ploughing": "plowing",
|
1200 |
+
"ploughman": "plowman",
|
1201 |
+
"ploughmen": "plowmen",
|
1202 |
+
"ploughs": "plows",
|
1203 |
+
"ploughshare": "plowshare",
|
1204 |
+
"ploughshares": "plowshares",
|
1205 |
+
"polarisation": "polarization",
|
1206 |
+
"polarise": "polarize",
|
1207 |
+
"polarised": "polarized",
|
1208 |
+
"polarises": "polarizes",
|
1209 |
+
"polarising": "polarizing",
|
1210 |
+
"politicisation": "politicization",
|
1211 |
+
"politicise": "politicize",
|
1212 |
+
"politicised": "politicized",
|
1213 |
+
"politicises": "politicizes",
|
1214 |
+
"politicising": "politicizing",
|
1215 |
+
"popularisation": "popularization",
|
1216 |
+
"popularise": "popularize",
|
1217 |
+
"popularised": "popularized",
|
1218 |
+
"popularises": "popularizes",
|
1219 |
+
"popularising": "popularizing",
|
1220 |
+
"pouffe": "pouf",
|
1221 |
+
"pouffes": "poufs",
|
1222 |
+
"practise": "practice",
|
1223 |
+
"practised": "practiced",
|
1224 |
+
"practises": "practices",
|
1225 |
+
"practising": "practicing",
|
1226 |
+
"praesidium": "presidium",
|
1227 |
+
"praesidiums": "presidiums",
|
1228 |
+
"pressurisation": "pressurization",
|
1229 |
+
"pressurise": "pressurize",
|
1230 |
+
"pressurised": "pressurized",
|
1231 |
+
"pressurises": "pressurizes",
|
1232 |
+
"pressurising": "pressurizing",
|
1233 |
+
"pretence": "pretense",
|
1234 |
+
"pretences": "pretenses",
|
1235 |
+
"primaeval": "primeval",
|
1236 |
+
"prioritisation": "prioritization",
|
1237 |
+
"prioritise": "prioritize",
|
1238 |
+
"prioritised": "prioritized",
|
1239 |
+
"prioritises": "prioritizes",
|
1240 |
+
"prioritising": "prioritizing",
|
1241 |
+
"privatisation": "privatization",
|
1242 |
+
"privatisations": "privatizations",
|
1243 |
+
"privatise": "privatize",
|
1244 |
+
"privatised": "privatized",
|
1245 |
+
"privatises": "privatizes",
|
1246 |
+
"privatising": "privatizing",
|
1247 |
+
"professionalisation": "professionalization",
|
1248 |
+
"professionalise": "professionalize",
|
1249 |
+
"professionalised": "professionalized",
|
1250 |
+
"professionalises": "professionalizes",
|
1251 |
+
"professionalising": "professionalizing",
|
1252 |
+
"programme": "program",
|
1253 |
+
"programmes": "programs",
|
1254 |
+
"prologue": "prolog",
|
1255 |
+
"prologues": "prologs",
|
1256 |
+
"propagandise": "propagandize",
|
1257 |
+
"propagandised": "propagandized",
|
1258 |
+
"propagandises": "propagandizes",
|
1259 |
+
"propagandising": "propagandizing",
|
1260 |
+
"proselytise": "proselytize",
|
1261 |
+
"proselytised": "proselytized",
|
1262 |
+
"proselytiser": "proselytizer",
|
1263 |
+
"proselytisers": "proselytizers",
|
1264 |
+
"proselytises": "proselytizes",
|
1265 |
+
"proselytising": "proselytizing",
|
1266 |
+
"psychoanalyse": "psychoanalyze",
|
1267 |
+
"psychoanalysed": "psychoanalyzed",
|
1268 |
+
"psychoanalyses": "psychoanalyzes",
|
1269 |
+
"psychoanalysing": "psychoanalyzing",
|
1270 |
+
"publicise": "publicize",
|
1271 |
+
"publicised": "publicized",
|
1272 |
+
"publicises": "publicizes",
|
1273 |
+
"publicising": "publicizing",
|
1274 |
+
"pulverisation": "pulverization",
|
1275 |
+
"pulverise": "pulverize",
|
1276 |
+
"pulverised": "pulverized",
|
1277 |
+
"pulverises": "pulverizes",
|
1278 |
+
"pulverising": "pulverizing",
|
1279 |
+
"pummelled": "pummel",
|
1280 |
+
"pummelling": "pummeled",
|
1281 |
+
"pyjama": "pajama",
|
1282 |
+
"pyjamas": "pajamas",
|
1283 |
+
"pzazz": "pizzazz",
|
1284 |
+
"quarrelled": "quarreled",
|
1285 |
+
"quarrelling": "quarreling",
|
1286 |
+
"radicalise": "radicalize",
|
1287 |
+
"radicalised": "radicalized",
|
1288 |
+
"radicalises": "radicalizes",
|
1289 |
+
"radicalising": "radicalizing",
|
1290 |
+
"rancour": "rancor",
|
1291 |
+
"randomise": "randomize",
|
1292 |
+
"randomised": "randomized",
|
1293 |
+
"randomises": "randomizes",
|
1294 |
+
"randomising": "randomizing",
|
1295 |
+
"rationalisation": "rationalization",
|
1296 |
+
"rationalisations": "rationalizations",
|
1297 |
+
"rationalise": "rationalize",
|
1298 |
+
"rationalised": "rationalized",
|
1299 |
+
"rationalises": "rationalizes",
|
1300 |
+
"rationalising": "rationalizing",
|
1301 |
+
"ravelled": "raveled",
|
1302 |
+
"ravelling": "raveling",
|
1303 |
+
"realisable": "realizable",
|
1304 |
+
"realisation": "realization",
|
1305 |
+
"realisations": "realizations",
|
1306 |
+
"realise": "realize",
|
1307 |
+
"realised": "realized",
|
1308 |
+
"realises": "realizes",
|
1309 |
+
"realising": "realizing",
|
1310 |
+
"recognisable": "recognizable",
|
1311 |
+
"recognisably": "recognizably",
|
1312 |
+
"recognisance": "recognizance",
|
1313 |
+
"recognise": "recognize",
|
1314 |
+
"recognised": "recognized",
|
1315 |
+
"recognises": "recognizes",
|
1316 |
+
"recognising": "recognizing",
|
1317 |
+
"reconnoitre": "reconnoiter",
|
1318 |
+
"reconnoitred": "reconnoitered",
|
1319 |
+
"reconnoitres": "reconnoiters",
|
1320 |
+
"reconnoitring": "reconnoitering",
|
1321 |
+
"refuelled": "refueled",
|
1322 |
+
"refuelling": "refueling",
|
1323 |
+
"regularisation": "regularization",
|
1324 |
+
"regularise": "regularize",
|
1325 |
+
"regularised": "regularized",
|
1326 |
+
"regularises": "regularizes",
|
1327 |
+
"regularising": "regularizing",
|
1328 |
+
"remodelled": "remodeled",
|
1329 |
+
"remodelling": "remodeling",
|
1330 |
+
"remould": "remold",
|
1331 |
+
"remoulded": "remolded",
|
1332 |
+
"remoulding": "remolding",
|
1333 |
+
"remoulds": "remolds",
|
1334 |
+
"reorganisation": "reorganization",
|
1335 |
+
"reorganisations": "reorganizations",
|
1336 |
+
"reorganise": "reorganize",
|
1337 |
+
"reorganised": "reorganized",
|
1338 |
+
"reorganises": "reorganizes",
|
1339 |
+
"reorganising": "reorganizing",
|
1340 |
+
"revelled": "reveled",
|
1341 |
+
"reveller": "reveler",
|
1342 |
+
"revellers": "revelers",
|
1343 |
+
"revelling": "reveling",
|
1344 |
+
"revitalise": "revitalize",
|
1345 |
+
"revitalised": "revitalized",
|
1346 |
+
"revitalises": "revitalizes",
|
1347 |
+
"revitalising": "revitalizing",
|
1348 |
+
"revolutionise": "revolutionize",
|
1349 |
+
"revolutionised": "revolutionized",
|
1350 |
+
"revolutionises": "revolutionizes",
|
1351 |
+
"revolutionising": "revolutionizing",
|
1352 |
+
"rhapsodise": "rhapsodize",
|
1353 |
+
"rhapsodised": "rhapsodized",
|
1354 |
+
"rhapsodises": "rhapsodizes",
|
1355 |
+
"rhapsodising": "rhapsodizing",
|
1356 |
+
"rigour": "rigor",
|
1357 |
+
"rigours": "rigors",
|
1358 |
+
"ritualised": "ritualized",
|
1359 |
+
"rivalled": "rivaled",
|
1360 |
+
"rivalling": "rivaling",
|
1361 |
+
"romanticise": "romanticize",
|
1362 |
+
"romanticised": "romanticized",
|
1363 |
+
"romanticises": "romanticizes",
|
1364 |
+
"romanticising": "romanticizing",
|
1365 |
+
"rumour": "rumor",
|
1366 |
+
"rumoured": "rumored",
|
1367 |
+
"rumours": "rumors",
|
1368 |
+
"sabre": "saber",
|
1369 |
+
"sabres": "sabers",
|
1370 |
+
"saltpetre": "saltpeter",
|
1371 |
+
"sanitise": "sanitize",
|
1372 |
+
"sanitised": "sanitized",
|
1373 |
+
"sanitises": "sanitizes",
|
1374 |
+
"sanitising": "sanitizing",
|
1375 |
+
"satirise": "satirize",
|
1376 |
+
"satirised": "satirized",
|
1377 |
+
"satirises": "satirizes",
|
1378 |
+
"satirising": "satirizing",
|
1379 |
+
"saviour": "savior",
|
1380 |
+
"saviours": "saviors",
|
1381 |
+
"savour": "savor",
|
1382 |
+
"savoured": "savored",
|
1383 |
+
"savouries": "savories",
|
1384 |
+
"savouring": "savoring",
|
1385 |
+
"savours": "savors",
|
1386 |
+
"savoury": "savory",
|
1387 |
+
"scandalise": "scandalize",
|
1388 |
+
"scandalised": "scandalized",
|
1389 |
+
"scandalises": "scandalizes",
|
1390 |
+
"scandalising": "scandalizing",
|
1391 |
+
"sceptic": "skeptic",
|
1392 |
+
"sceptical": "skeptical",
|
1393 |
+
"sceptically": "skeptically",
|
1394 |
+
"scepticism": "skepticism",
|
1395 |
+
"sceptics": "skeptics",
|
1396 |
+
"sceptre": "scepter",
|
1397 |
+
"sceptres": "scepters",
|
1398 |
+
"scrutinise": "scrutinize",
|
1399 |
+
"scrutinised": "scrutinized",
|
1400 |
+
"scrutinises": "scrutinizes",
|
1401 |
+
"scrutinising": "scrutinizing",
|
1402 |
+
"secularisation": "secularization",
|
1403 |
+
"secularise": "secularize",
|
1404 |
+
"secularised": "secularized",
|
1405 |
+
"secularises": "secularizes",
|
1406 |
+
"secularising": "secularizing",
|
1407 |
+
"sensationalise": "sensationalize",
|
1408 |
+
"sensationalised": "sensationalized",
|
1409 |
+
"sensationalises": "sensationalizes",
|
1410 |
+
"sensationalising": "sensationalizing",
|
1411 |
+
"sensitise": "sensitize",
|
1412 |
+
"sensitised": "sensitized",
|
1413 |
+
"sensitises": "sensitizes",
|
1414 |
+
"sensitising": "sensitizing",
|
1415 |
+
"sentimentalise": "sentimentalize",
|
1416 |
+
"sentimentalised": "sentimentalized",
|
1417 |
+
"sentimentalises": "sentimentalizes",
|
1418 |
+
"sentimentalising": "sentimentalizing",
|
1419 |
+
"sepulchre": "sepulcher",
|
1420 |
+
"sepulchres": "sepulchers",
|
1421 |
+
"serialisation": "serialization",
|
1422 |
+
"serialisations": "serializations",
|
1423 |
+
"serialise": "serialize",
|
1424 |
+
"serialised": "serialized",
|
1425 |
+
"serialises": "serializes",
|
1426 |
+
"serialising": "serializing",
|
1427 |
+
"sermonise": "sermonize",
|
1428 |
+
"sermonised": "sermonized",
|
1429 |
+
"sermonises": "sermonizes",
|
1430 |
+
"sermonising": "sermonizing",
|
1431 |
+
"sheikh": "sheik",
|
1432 |
+
"shovelled": "shoveled",
|
1433 |
+
"shovelling": "shoveling",
|
1434 |
+
"shrivelled": "shriveled",
|
1435 |
+
"shrivelling": "shriveling",
|
1436 |
+
"signalise": "signalize",
|
1437 |
+
"signalised": "signalized",
|
1438 |
+
"signalises": "signalizes",
|
1439 |
+
"signalising": "signalizing",
|
1440 |
+
"signalled": "signaled",
|
1441 |
+
"signalling": "signaling",
|
1442 |
+
"smoulder": "smolder",
|
1443 |
+
"smouldered": "smoldered",
|
1444 |
+
"smouldering": "smoldering",
|
1445 |
+
"smoulders": "smolders",
|
1446 |
+
"snivelled": "sniveled",
|
1447 |
+
"snivelling": "sniveling",
|
1448 |
+
"snorkelled": "snorkeled",
|
1449 |
+
"snorkelling": "snorkeling",
|
1450 |
+
"snowplough": "snowplow",
|
1451 |
+
"snowploughs": "snowplow",
|
1452 |
+
"socialisation": "socialization",
|
1453 |
+
"socialise": "socialize",
|
1454 |
+
"socialised": "socialized",
|
1455 |
+
"socialises": "socializes",
|
1456 |
+
"socialising": "socializing",
|
1457 |
+
"sodomise": "sodomize",
|
1458 |
+
"sodomised": "sodomized",
|
1459 |
+
"sodomises": "sodomizes",
|
1460 |
+
"sodomising": "sodomizing",
|
1461 |
+
"solemnise": "solemnize",
|
1462 |
+
"solemnised": "solemnized",
|
1463 |
+
"solemnises": "solemnizes",
|
1464 |
+
"solemnising": "solemnizing",
|
1465 |
+
"sombre": "somber",
|
1466 |
+
"specialisation": "specialization",
|
1467 |
+
"specialisations": "specializations",
|
1468 |
+
"specialise": "specialize",
|
1469 |
+
"specialised": "specialized",
|
1470 |
+
"specialises": "specializes",
|
1471 |
+
"specialising": "specializing",
|
1472 |
+
"spectre": "specter",
|
1473 |
+
"spectres": "specters",
|
1474 |
+
"spiralled": "spiraled",
|
1475 |
+
"spiralling": "spiraling",
|
1476 |
+
"splendour": "splendor",
|
1477 |
+
"splendours": "splendors",
|
1478 |
+
"squirrelled": "squirreled",
|
1479 |
+
"squirrelling": "squirreling",
|
1480 |
+
"stabilisation": "stabilization",
|
1481 |
+
"stabilise": "stabilize",
|
1482 |
+
"stabilised": "stabilized",
|
1483 |
+
"stabiliser": "stabilizer",
|
1484 |
+
"stabilisers": "stabilizers",
|
1485 |
+
"stabilises": "stabilizes",
|
1486 |
+
"stabilising": "stabilizing",
|
1487 |
+
"standardisation": "standardization",
|
1488 |
+
"standardise": "standardize",
|
1489 |
+
"standardised": "standardized",
|
1490 |
+
"standardises": "standardizes",
|
1491 |
+
"standardising": "standardizing",
|
1492 |
+
"stencilled": "stenciled",
|
1493 |
+
"stencilling": "stenciling",
|
1494 |
+
"sterilisation": "sterilization",
|
1495 |
+
"sterilisations": "sterilizations",
|
1496 |
+
"sterilise": "sterilize",
|
1497 |
+
"sterilised": "sterilized",
|
1498 |
+
"steriliser": "sterilizer",
|
1499 |
+
"sterilisers": "sterilizers",
|
1500 |
+
"sterilises": "sterilizes",
|
1501 |
+
"sterilising": "sterilizing",
|
1502 |
+
"stigmatisation": "stigmatization",
|
1503 |
+
"stigmatise": "stigmatize",
|
1504 |
+
"stigmatised": "stigmatized",
|
1505 |
+
"stigmatises": "stigmatizes",
|
1506 |
+
"stigmatising": "stigmatizing",
|
1507 |
+
"storey": "story",
|
1508 |
+
"storeys": "stories",
|
1509 |
+
"subsidisation": "subsidization",
|
1510 |
+
"subsidise": "subsidize",
|
1511 |
+
"subsidised": "subsidized",
|
1512 |
+
"subsidiser": "subsidizer",
|
1513 |
+
"subsidisers": "subsidizers",
|
1514 |
+
"subsidises": "subsidizes",
|
1515 |
+
"subsidising": "subsidizing",
|
1516 |
+
"succour": "succor",
|
1517 |
+
"succoured": "succored",
|
1518 |
+
"succouring": "succoring",
|
1519 |
+
"succours": "succors",
|
1520 |
+
"sulphate": "sulfate",
|
1521 |
+
"sulphates": "sulfates",
|
1522 |
+
"sulphide": "sulfide",
|
1523 |
+
"sulphides": "sulfides",
|
1524 |
+
"sulphur": "sulfur",
|
1525 |
+
"sulphurous": "sulfurous",
|
1526 |
+
"summarise": "summarize",
|
1527 |
+
"summarised": "summarized",
|
1528 |
+
"summarises": "summarizes",
|
1529 |
+
"summarising": "summarizing",
|
1530 |
+
"swivelled": "swiveled",
|
1531 |
+
"swivelling": "swiveling",
|
1532 |
+
"symbolise": "symbolize",
|
1533 |
+
"symbolised": "symbolized",
|
1534 |
+
"symbolises": "symbolizes",
|
1535 |
+
"symbolising": "symbolizing",
|
1536 |
+
"sympathise": "sympathize",
|
1537 |
+
"sympathised": "sympathized",
|
1538 |
+
"sympathiser": "sympathizer",
|
1539 |
+
"sympathisers": "sympathizers",
|
1540 |
+
"sympathises": "sympathizes",
|
1541 |
+
"sympathising": "sympathizing",
|
1542 |
+
"synchronisation": "synchronization",
|
1543 |
+
"synchronise": "synchronize",
|
1544 |
+
"synchronised": "synchronized",
|
1545 |
+
"synchronises": "synchronizes",
|
1546 |
+
"synchronising": "synchronizing",
|
1547 |
+
"synthesise": "synthesize",
|
1548 |
+
"synthesised": "synthesized",
|
1549 |
+
"synthesiser": "synthesizer",
|
1550 |
+
"synthesisers": "synthesizers",
|
1551 |
+
"synthesises": "synthesizes",
|
1552 |
+
"synthesising": "synthesizing",
|
1553 |
+
"syphon": "siphon",
|
1554 |
+
"syphoned": "siphoned",
|
1555 |
+
"syphoning": "siphoning",
|
1556 |
+
"syphons": "siphons",
|
1557 |
+
"systematisation": "systematization",
|
1558 |
+
"systematise": "systematize",
|
1559 |
+
"systematised": "systematized",
|
1560 |
+
"systematises": "systematizes",
|
1561 |
+
"systematising": "systematizing",
|
1562 |
+
"tantalise": "tantalize",
|
1563 |
+
"tantalised": "tantalized",
|
1564 |
+
"tantalises": "tantalizes",
|
1565 |
+
"tantalising": "tantalizing",
|
1566 |
+
"tantalisingly": "tantalizingly",
|
1567 |
+
"tasselled": "tasseled",
|
1568 |
+
"technicolour": "technicolor",
|
1569 |
+
"temporise": "temporize",
|
1570 |
+
"temporised": "temporized",
|
1571 |
+
"temporises": "temporizes",
|
1572 |
+
"temporising": "temporizing",
|
1573 |
+
"tenderise": "tenderize",
|
1574 |
+
"tenderised": "tenderized",
|
1575 |
+
"tenderises": "tenderizes",
|
1576 |
+
"tenderising": "tenderizing",
|
1577 |
+
"terrorise": "terrorize",
|
1578 |
+
"terrorised": "terrorized",
|
1579 |
+
"terrorises": "terrorizes",
|
1580 |
+
"terrorising": "terrorizing",
|
1581 |
+
"theatre": "theater",
|
1582 |
+
"theatregoer": "theatergoer",
|
1583 |
+
"theatregoers": "theatergoers",
|
1584 |
+
"theatres": "theaters",
|
1585 |
+
"theorise": "theorize",
|
1586 |
+
"theorised": "theorized",
|
1587 |
+
"theorises": "theorizes",
|
1588 |
+
"theorising": "theorizing",
|
1589 |
+
"tonne": "ton",
|
1590 |
+
"tonnes": "tons",
|
1591 |
+
"towelled": "toweled",
|
1592 |
+
"towelling": "toweling",
|
1593 |
+
"toxaemia": "toxemia",
|
1594 |
+
"tranquillise": "tranquilize",
|
1595 |
+
"tranquillised": "tranquilized",
|
1596 |
+
"tranquilliser": "tranquilizer",
|
1597 |
+
"tranquillisers": "tranquilizers",
|
1598 |
+
"tranquillises": "tranquilizes",
|
1599 |
+
"tranquillising": "tranquilizing",
|
1600 |
+
"tranquillity": "tranquility",
|
1601 |
+
"tranquillize": "tranquilize",
|
1602 |
+
"tranquillized": "tranquilized",
|
1603 |
+
"tranquillizer": "tranquilizer",
|
1604 |
+
"tranquillizers": "tranquilizers",
|
1605 |
+
"tranquillizes": "tranquilizes",
|
1606 |
+
"tranquillizing": "tranquilizing",
|
1607 |
+
"tranquilly": "tranquility",
|
1608 |
+
"transistorised": "transistorized",
|
1609 |
+
"traumatise": "traumatize",
|
1610 |
+
"traumatised": "traumatized",
|
1611 |
+
"traumatises": "traumatizes",
|
1612 |
+
"traumatising": "traumatizing",
|
1613 |
+
"travelled": "traveled",
|
1614 |
+
"traveller": "traveler",
|
1615 |
+
"travellers": "travelers",
|
1616 |
+
"travelling": "traveling",
|
1617 |
+
"travelog": "travelogue",
|
1618 |
+
"travelogs": "travelogues",
|
1619 |
+
"trialled": "trialed",
|
1620 |
+
"trialling": "trialing",
|
1621 |
+
"tricolour": "tricolor",
|
1622 |
+
"tricolours": "tricolors",
|
1623 |
+
"trivialise": "trivialize",
|
1624 |
+
"trivialised": "trivialized",
|
1625 |
+
"trivialises": "trivializes",
|
1626 |
+
"trivialising": "trivializing",
|
1627 |
+
"tumour": "tumor",
|
1628 |
+
"tumours": "tumors",
|
1629 |
+
"tunnelled": "tunneled",
|
1630 |
+
"tunnelling": "tunneling",
|
1631 |
+
"tyrannise": "tyrannize",
|
1632 |
+
"tyrannised": "tyrannized",
|
1633 |
+
"tyrannises": "tyrannizes",
|
1634 |
+
"tyrannising": "tyrannizing",
|
1635 |
+
"tyre": "tire",
|
1636 |
+
"tyres": "tires",
|
1637 |
+
"unauthorised": "unauthorized",
|
1638 |
+
"uncivilised": "uncivilized",
|
1639 |
+
"underutilised": "underutilized",
|
1640 |
+
"unequalled": "unequaled",
|
1641 |
+
"unfavourable": "unfavorable",
|
1642 |
+
"unfavourably": "unfavorably",
|
1643 |
+
"unionisation": "unionization",
|
1644 |
+
"unionise": "unionize",
|
1645 |
+
"unionised": "unionized",
|
1646 |
+
"unionises": "unionizes",
|
1647 |
+
"unionising": "unionizing",
|
1648 |
+
"unorganised": "unorganized",
|
1649 |
+
"unravelled": "unraveled",
|
1650 |
+
"unravelling": "unraveling",
|
1651 |
+
"unrecognisable": "unrecognizable",
|
1652 |
+
"unrecognised": "unrecognized",
|
1653 |
+
"unrivalled": "unrivaled",
|
1654 |
+
"unsavoury": "unsavory",
|
1655 |
+
"untrammelled": "untrammeled",
|
1656 |
+
"urbanisation": "urbanization",
|
1657 |
+
"urbanise": "urbanize",
|
1658 |
+
"urbanised": "urbanized",
|
1659 |
+
"urbanises": "urbanizes",
|
1660 |
+
"urbanising": "urbanizing",
|
1661 |
+
"utilisable": "utilizable",
|
1662 |
+
"utilisation": "utilization",
|
1663 |
+
"utilise": "utilize",
|
1664 |
+
"utilised": "utilized",
|
1665 |
+
"utilises": "utilizes",
|
1666 |
+
"utilising": "utilizing",
|
1667 |
+
"valour": "valor",
|
1668 |
+
"vandalise": "vandalize",
|
1669 |
+
"vandalised": "vandalized",
|
1670 |
+
"vandalises": "vandalizes",
|
1671 |
+
"vandalising": "vandalizing",
|
1672 |
+
"vaporisation": "vaporization",
|
1673 |
+
"vaporise": "vaporize",
|
1674 |
+
"vaporised": "vaporized",
|
1675 |
+
"vaporises": "vaporizes",
|
1676 |
+
"vaporising": "vaporizing",
|
1677 |
+
"vapour": "vapor",
|
1678 |
+
"vapours": "vapors",
|
1679 |
+
"verbalise": "verbalize",
|
1680 |
+
"verbalised": "verbalized",
|
1681 |
+
"verbalises": "verbalizes",
|
1682 |
+
"verbalising": "verbalizing",
|
1683 |
+
"victimisation": "victimization",
|
1684 |
+
"victimise": "victimize",
|
1685 |
+
"victimised": "victimized",
|
1686 |
+
"victimises": "victimizes",
|
1687 |
+
"victimising": "victimizing",
|
1688 |
+
"videodisc": "videodisk",
|
1689 |
+
"videodiscs": "videodisks",
|
1690 |
+
"vigour": "vigor",
|
1691 |
+
"visualisation": "visualization",
|
1692 |
+
"visualisations": "visualizations",
|
1693 |
+
"visualise": "visualize",
|
1694 |
+
"visualised": "visualized",
|
1695 |
+
"visualises": "visualizes",
|
1696 |
+
"visualising": "visualizing",
|
1697 |
+
"vocalisation": "vocalization",
|
1698 |
+
"vocalisations": "vocalizations",
|
1699 |
+
"vocalise": "vocalize",
|
1700 |
+
"vocalised": "vocalized",
|
1701 |
+
"vocalises": "vocalizes",
|
1702 |
+
"vocalising": "vocalizing",
|
1703 |
+
"vulcanised": "vulcanized",
|
1704 |
+
"vulgarisation": "vulgarization",
|
1705 |
+
"vulgarise": "vulgarize",
|
1706 |
+
"vulgarised": "vulgarized",
|
1707 |
+
"vulgarises": "vulgarizes",
|
1708 |
+
"vulgarising": "vulgarizing",
|
1709 |
+
"waggon": "wagon",
|
1710 |
+
"waggons": "wagons",
|
1711 |
+
"watercolour": "watercolor",
|
1712 |
+
"watercolours": "watercolors",
|
1713 |
+
"weaselled": "weaseled",
|
1714 |
+
"weaselling": "weaseling",
|
1715 |
+
"westernisation": "westernization",
|
1716 |
+
"westernise": "westernize",
|
1717 |
+
"westernised": "westernized",
|
1718 |
+
"westernises": "westernizes",
|
1719 |
+
"westernising": "westernizing",
|
1720 |
+
"womanise": "womanize",
|
1721 |
+
"womanised": "womanized",
|
1722 |
+
"womaniser": "womanizer",
|
1723 |
+
"womanisers": "womanizers",
|
1724 |
+
"womanises": "womanizes",
|
1725 |
+
"womanising": "womanizing",
|
1726 |
+
"woollen": "woolen",
|
1727 |
+
"woollens": "woolens",
|
1728 |
+
"woollies": "woolies",
|
1729 |
+
"woolly": "wooly",
|
1730 |
+
"worshipped": "worshiped",
|
1731 |
+
"worshipping": "worshiping",
|
1732 |
+
"worshipper": "worshiper",
|
1733 |
+
"yodelled": "yodeled",
|
1734 |
+
"yodelling": "yodeling",
|
1735 |
+
"yoghourt": "yogurt",
|
1736 |
+
"yoghourts": "yogurts",
|
1737 |
+
"yoghurt": "yogurt",
|
1738 |
+
"yoghurts": "yogurts"
|
1739 |
+
}
|
txt_norm/english.py
ADDED
@@ -0,0 +1,691 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
import re
|
4 |
+
from fractions import Fraction
|
5 |
+
from typing import Iterator, List, Match, Optional, Union
|
6 |
+
|
7 |
+
from more_itertools import windowed
|
8 |
+
|
9 |
+
from .basic import remove_symbols_and_diacritics
|
10 |
+
|
11 |
+
|
12 |
+
class EnglishNumberNormalizer:
|
13 |
+
"""
|
14 |
+
Convert any spelled-out numbers into arabic numbers, while handling:
|
15 |
+
|
16 |
+
- remove any commas
|
17 |
+
- keep the suffixes such as: `1960s`, `274th`, `32nd`, etc.
|
18 |
+
- spell out currency symbols after the number. e.g. `$20 million` -> `20000000 dollars` # noqa e501
|
19 |
+
- spell out `one` and `ones`
|
20 |
+
- interpret successive single-digit numbers as nominal: `one oh one` -> `101` # noqa e501
|
21 |
+
"""
|
22 |
+
|
23 |
+
def __init__(self):
|
24 |
+
super().__init__()
|
25 |
+
|
26 |
+
self.zeros = {"o", "zero"}
|
27 |
+
self.ones = {
|
28 |
+
name: i
|
29 |
+
for i, name in enumerate(
|
30 |
+
[
|
31 |
+
"one",
|
32 |
+
"two",
|
33 |
+
"three",
|
34 |
+
"four",
|
35 |
+
"five",
|
36 |
+
"six",
|
37 |
+
"seven",
|
38 |
+
"eight",
|
39 |
+
"nine",
|
40 |
+
"ten",
|
41 |
+
"eleven",
|
42 |
+
"twelve",
|
43 |
+
"thirteen",
|
44 |
+
"fourteen",
|
45 |
+
"fifteen",
|
46 |
+
"sixteen",
|
47 |
+
"seventeen",
|
48 |
+
"eighteen",
|
49 |
+
"nineteen",
|
50 |
+
],
|
51 |
+
start=1,
|
52 |
+
)
|
53 |
+
}
|
54 |
+
self.ones_plural = {
|
55 |
+
"sixes" if name == "six" else name + "s": (value, "s")
|
56 |
+
for name, value in self.ones.items()
|
57 |
+
}
|
58 |
+
self.ones_ordinal = {
|
59 |
+
"zeroth": (0, "th"),
|
60 |
+
"first": (1, "st"),
|
61 |
+
"second": (2, "nd"),
|
62 |
+
"third": (3, "rd"),
|
63 |
+
"fifth": (5, "th"),
|
64 |
+
"twelfth": (12, "th"),
|
65 |
+
**{
|
66 |
+
name + ("h" if name.endswith("t") else "th"): (value, "th")
|
67 |
+
for name, value in self.ones.items()
|
68 |
+
if value > 3 and value != 5 and value != 12
|
69 |
+
},
|
70 |
+
}
|
71 |
+
self.ones_suffixed = {**self.ones_plural, **self.ones_ordinal}
|
72 |
+
|
73 |
+
self.tens = {
|
74 |
+
"twenty": 20,
|
75 |
+
"thirty": 30,
|
76 |
+
"forty": 40,
|
77 |
+
"fifty": 50,
|
78 |
+
"sixty": 60,
|
79 |
+
"seventy": 70,
|
80 |
+
"eighty": 80,
|
81 |
+
"ninety": 90,
|
82 |
+
}
|
83 |
+
self.tens_plural = {
|
84 |
+
name.replace("y", "ies"): (value, "s") for name, value in self.tens.items()
|
85 |
+
}
|
86 |
+
self.tens_ordinal = {
|
87 |
+
name.replace("y", "ieth"): (value, "th")
|
88 |
+
for name, value in self.tens.items()
|
89 |
+
}
|
90 |
+
self.tens_suffixed = {**self.tens_plural, **self.tens_ordinal}
|
91 |
+
|
92 |
+
self.multipliers = {
|
93 |
+
"hundred": 100,
|
94 |
+
"thousand": 1_000,
|
95 |
+
"million": 1_000_000,
|
96 |
+
"billion": 1_000_000_000,
|
97 |
+
"trillion": 1_000_000_000_000,
|
98 |
+
"quadrillion": 1_000_000_000_000_000,
|
99 |
+
"quintillion": 1_000_000_000_000_000_000,
|
100 |
+
"sextillion": 1_000_000_000_000_000_000_000,
|
101 |
+
"septillion": 1_000_000_000_000_000_000_000_000,
|
102 |
+
"octillion": 1_000_000_000_000_000_000_000_000_000,
|
103 |
+
"nonillion": 1_000_000_000_000_000_000_000_000_000_000,
|
104 |
+
"decillion": 1_000_000_000_000_000_000_000_000_000_000_000,
|
105 |
+
}
|
106 |
+
self.multipliers_plural = {
|
107 |
+
name + "s": (value, "s") for name, value in self.multipliers.items()
|
108 |
+
}
|
109 |
+
self.multipliers_ordinal = {
|
110 |
+
name + "th": (value, "th") for name, value in self.multipliers.items()
|
111 |
+
}
|
112 |
+
self.multipliers_suffixed = {
|
113 |
+
**self.multipliers_plural,
|
114 |
+
**self.multipliers_ordinal,
|
115 |
+
}
|
116 |
+
self.decimals = {*self.ones, *self.tens, *self.zeros}
|
117 |
+
|
118 |
+
self.preceding_prefixers = {
|
119 |
+
"minus": "-",
|
120 |
+
"negative": "-",
|
121 |
+
"plus": "+",
|
122 |
+
"positive": "+",
|
123 |
+
}
|
124 |
+
self.following_prefixers = {
|
125 |
+
"pound": "£",
|
126 |
+
"pounds": "£",
|
127 |
+
"euro": "€",
|
128 |
+
"euros": "€",
|
129 |
+
"dollar": "$",
|
130 |
+
"dollars": "$",
|
131 |
+
"cent": "¢",
|
132 |
+
"cents": "¢",
|
133 |
+
}
|
134 |
+
self.prefixes = set(
|
135 |
+
list(self.preceding_prefixers.values())
|
136 |
+
+ list(self.following_prefixers.values())
|
137 |
+
)
|
138 |
+
self.suffixers = {
|
139 |
+
"per": {"cent": "%"},
|
140 |
+
"percent": "%",
|
141 |
+
}
|
142 |
+
self.specials = {"and", "double", "triple", "point"}
|
143 |
+
|
144 |
+
self.words = set(
|
145 |
+
[
|
146 |
+
key
|
147 |
+
for mapping in [
|
148 |
+
self.zeros,
|
149 |
+
self.ones,
|
150 |
+
self.ones_suffixed,
|
151 |
+
self.tens,
|
152 |
+
self.tens_suffixed,
|
153 |
+
self.multipliers,
|
154 |
+
self.multipliers_suffixed,
|
155 |
+
self.preceding_prefixers,
|
156 |
+
self.following_prefixers,
|
157 |
+
self.suffixers,
|
158 |
+
self.specials,
|
159 |
+
]
|
160 |
+
for key in mapping
|
161 |
+
]
|
162 |
+
)
|
163 |
+
self.literal_words = {"one", "ones"}
|
164 |
+
|
165 |
+
def process_words(self, words: List[str]) -> Iterator[str]:
|
166 |
+
prefix: Optional[str] = None
|
167 |
+
value: Optional[Union[str, int]] = None
|
168 |
+
skip = False
|
169 |
+
|
170 |
+
def to_fraction(s: str):
|
171 |
+
try:
|
172 |
+
return Fraction(s)
|
173 |
+
except ValueError:
|
174 |
+
return None
|
175 |
+
|
176 |
+
def output(result: Union[str, int]):
|
177 |
+
nonlocal prefix, value
|
178 |
+
result = str(result)
|
179 |
+
if prefix is not None:
|
180 |
+
result = prefix + result
|
181 |
+
value = None
|
182 |
+
prefix = None
|
183 |
+
return result
|
184 |
+
|
185 |
+
if len(words) == 0:
|
186 |
+
return
|
187 |
+
|
188 |
+
for prev, current, next in windowed([None] + words + [None], 3):
|
189 |
+
if skip:
|
190 |
+
skip = False
|
191 |
+
continue
|
192 |
+
|
193 |
+
next_is_numeric = next is not None and re.match(r"^\d+(\.\d+)?$", next)
|
194 |
+
has_prefix = current[0] in self.prefixes
|
195 |
+
current_without_prefix = current[1:] if has_prefix else current
|
196 |
+
if re.match(r"^\d+(\.\d+)?$", current_without_prefix):
|
197 |
+
# arabic numbers (potentially with signs and fractions)
|
198 |
+
f = to_fraction(current_without_prefix)
|
199 |
+
assert f is not None
|
200 |
+
if value is not None:
|
201 |
+
if isinstance(value, str) and value.endswith("."):
|
202 |
+
# concatenate decimals / ip address components
|
203 |
+
value = str(value) + str(current)
|
204 |
+
continue
|
205 |
+
else:
|
206 |
+
yield output(value)
|
207 |
+
|
208 |
+
prefix = current[0] if has_prefix else prefix
|
209 |
+
if f.denominator == 1:
|
210 |
+
value = f.numerator # store integers as int
|
211 |
+
else:
|
212 |
+
value = current_without_prefix
|
213 |
+
elif current not in self.words:
|
214 |
+
# non-numeric words
|
215 |
+
if value is not None:
|
216 |
+
yield output(value)
|
217 |
+
yield output(current)
|
218 |
+
elif current in self.zeros:
|
219 |
+
value = str(value or "") + "0"
|
220 |
+
elif current in self.ones:
|
221 |
+
ones = self.ones[current]
|
222 |
+
|
223 |
+
if value is None:
|
224 |
+
value = ones
|
225 |
+
elif isinstance(value, str) or prev in self.ones:
|
226 |
+
if (
|
227 |
+
prev in self.tens and ones < 10
|
228 |
+
): # replace the last zero with the digit
|
229 |
+
assert value[-1] == "0"
|
230 |
+
value = value[:-1] + str(ones)
|
231 |
+
else:
|
232 |
+
value = str(value) + str(ones)
|
233 |
+
elif ones < 10:
|
234 |
+
if value % 10 == 0:
|
235 |
+
value += ones
|
236 |
+
else:
|
237 |
+
value = str(value) + str(ones)
|
238 |
+
else: # eleven to nineteen
|
239 |
+
if value % 100 == 0:
|
240 |
+
value += ones
|
241 |
+
else:
|
242 |
+
value = str(value) + str(ones)
|
243 |
+
elif current in self.ones_suffixed:
|
244 |
+
# ordinal or cardinal; yield the number right away
|
245 |
+
ones, suffix = self.ones_suffixed[current]
|
246 |
+
if value is None:
|
247 |
+
yield output(str(ones) + suffix)
|
248 |
+
elif isinstance(value, str) or prev in self.ones:
|
249 |
+
if prev in self.tens and ones < 10:
|
250 |
+
assert value[-1] == "0"
|
251 |
+
yield output(value[:-1] + str(ones) + suffix)
|
252 |
+
else:
|
253 |
+
yield output(str(value) + str(ones) + suffix)
|
254 |
+
elif ones < 10:
|
255 |
+
if value % 10 == 0:
|
256 |
+
yield output(str(value + ones) + suffix)
|
257 |
+
else:
|
258 |
+
yield output(str(value) + str(ones) + suffix)
|
259 |
+
else: # eleven to nineteen
|
260 |
+
if value % 100 == 0:
|
261 |
+
yield output(str(value + ones) + suffix)
|
262 |
+
else:
|
263 |
+
yield output(str(value) + str(ones) + suffix)
|
264 |
+
value = None
|
265 |
+
elif current in self.tens:
|
266 |
+
tens = self.tens[current]
|
267 |
+
if value is None:
|
268 |
+
value = tens
|
269 |
+
elif isinstance(value, str):
|
270 |
+
value = str(value) + str(tens)
|
271 |
+
else:
|
272 |
+
if value % 100 == 0:
|
273 |
+
value += tens
|
274 |
+
else:
|
275 |
+
value = str(value) + str(tens)
|
276 |
+
elif current in self.tens_suffixed:
|
277 |
+
# ordinal or cardinal; yield the number right away
|
278 |
+
tens, suffix = self.tens_suffixed[current]
|
279 |
+
if value is None:
|
280 |
+
yield output(str(tens) + suffix)
|
281 |
+
elif isinstance(value, str):
|
282 |
+
yield output(str(value) + str(tens) + suffix)
|
283 |
+
else:
|
284 |
+
if value % 100 == 0:
|
285 |
+
yield output(str(value + tens) + suffix)
|
286 |
+
else:
|
287 |
+
yield output(str(value) + str(tens) + suffix)
|
288 |
+
elif current in self.multipliers:
|
289 |
+
multiplier = self.multipliers[current]
|
290 |
+
if value is None:
|
291 |
+
value = multiplier
|
292 |
+
elif isinstance(value, str) or value == 0:
|
293 |
+
f = to_fraction(value)
|
294 |
+
p = f * multiplier if f is not None else None
|
295 |
+
if f is not None and p.denominator == 1:
|
296 |
+
value = p.numerator
|
297 |
+
else:
|
298 |
+
yield output(value)
|
299 |
+
value = multiplier
|
300 |
+
else:
|
301 |
+
before = value // 1000 * 1000
|
302 |
+
residual = value % 1000
|
303 |
+
value = before + residual * multiplier
|
304 |
+
elif current in self.multipliers_suffixed:
|
305 |
+
multiplier, suffix = self.multipliers_suffixed[current]
|
306 |
+
if value is None:
|
307 |
+
yield output(str(multiplier) + suffix)
|
308 |
+
elif isinstance(value, str):
|
309 |
+
f = to_fraction(value)
|
310 |
+
p = f * multiplier if f is not None else None
|
311 |
+
if f is not None and p.denominator == 1:
|
312 |
+
yield output(str(p.numerator) + suffix)
|
313 |
+
else:
|
314 |
+
yield output(value)
|
315 |
+
yield output(str(multiplier) + suffix)
|
316 |
+
else: # int
|
317 |
+
before = value // 1000 * 1000
|
318 |
+
residual = value % 1000
|
319 |
+
value = before + residual * multiplier
|
320 |
+
yield output(str(value) + suffix)
|
321 |
+
value = None
|
322 |
+
elif current in self.preceding_prefixers:
|
323 |
+
# apply prefix (positive, minus, etc.) if it precedes a number
|
324 |
+
if value is not None:
|
325 |
+
yield output(value)
|
326 |
+
|
327 |
+
if next in self.words or next_is_numeric:
|
328 |
+
prefix = self.preceding_prefixers[current]
|
329 |
+
else:
|
330 |
+
yield output(current)
|
331 |
+
elif current in self.following_prefixers:
|
332 |
+
# apply prefix (dollars, cents, etc.) only after a number
|
333 |
+
if value is not None:
|
334 |
+
prefix = self.following_prefixers[current]
|
335 |
+
yield output(value)
|
336 |
+
else:
|
337 |
+
yield output(current)
|
338 |
+
elif current in self.suffixers:
|
339 |
+
# apply suffix symbols (percent -> '%')
|
340 |
+
if value is not None:
|
341 |
+
suffix = self.suffixers[current]
|
342 |
+
if isinstance(suffix, dict):
|
343 |
+
if next in suffix:
|
344 |
+
yield output(str(value) + suffix[next])
|
345 |
+
skip = True
|
346 |
+
else:
|
347 |
+
yield output(value)
|
348 |
+
yield output(current)
|
349 |
+
else:
|
350 |
+
yield output(str(value) + suffix)
|
351 |
+
else:
|
352 |
+
yield output(current)
|
353 |
+
elif current in self.specials:
|
354 |
+
if next not in self.words and not next_is_numeric:
|
355 |
+
# apply special handling
|
356 |
+
# only if the next word can be numeric
|
357 |
+
if value is not None:
|
358 |
+
yield output(value)
|
359 |
+
yield output(current)
|
360 |
+
elif current == "and":
|
361 |
+
# ignore "and" after hundreds, thousands, etc.
|
362 |
+
if prev not in self.multipliers:
|
363 |
+
if value is not None:
|
364 |
+
yield output(value)
|
365 |
+
yield output(current)
|
366 |
+
elif current == "double" or current == "triple":
|
367 |
+
if next in self.ones or next in self.zeros:
|
368 |
+
repeats = 2 if current == "double" else 3
|
369 |
+
ones = self.ones.get(next, 0)
|
370 |
+
value = str(value or "") + str(ones) * repeats
|
371 |
+
skip = True
|
372 |
+
else:
|
373 |
+
if value is not None:
|
374 |
+
yield output(value)
|
375 |
+
yield output(current)
|
376 |
+
elif current == "point":
|
377 |
+
if next in self.decimals or next_is_numeric:
|
378 |
+
value = str(value or "") + "."
|
379 |
+
else:
|
380 |
+
# should all have been covered at this point
|
381 |
+
raise ValueError(f"Unexpected token: {current}")
|
382 |
+
else:
|
383 |
+
# all should have been covered at this point
|
384 |
+
raise ValueError(f"Unexpected token: {current}")
|
385 |
+
|
386 |
+
if value is not None:
|
387 |
+
yield output(value)
|
388 |
+
|
389 |
+
def preprocess(self, s: str):
|
390 |
+
# replace "<number> and a half" with "<number> point five"
|
391 |
+
results = []
|
392 |
+
|
393 |
+
segments = re.split(r"\band\s+a\s+half\b", s)
|
394 |
+
for i, segment in enumerate(segments):
|
395 |
+
if len(segment.strip()) == 0:
|
396 |
+
continue
|
397 |
+
if i == len(segments) - 1:
|
398 |
+
results.append(segment)
|
399 |
+
else:
|
400 |
+
results.append(segment)
|
401 |
+
last_word = segment.rsplit(maxsplit=2)[-1]
|
402 |
+
if last_word in self.decimals or last_word in self.multipliers:
|
403 |
+
results.append("point five")
|
404 |
+
else:
|
405 |
+
results.append("and a half")
|
406 |
+
|
407 |
+
s = " ".join(results)
|
408 |
+
|
409 |
+
# put a space at number/letter boundary
|
410 |
+
s = re.sub(r"([a-z])([0-9])", r"\1 \2", s)
|
411 |
+
s = re.sub(r"([0-9])([a-z])", r"\1 \2", s)
|
412 |
+
|
413 |
+
# but remove spaces which could be a suffix
|
414 |
+
s = re.sub(r"([0-9])\s+(st|nd|rd|th|s)\b", r"\1\2", s)
|
415 |
+
|
416 |
+
return s
|
417 |
+
|
418 |
+
def postprocess(self, s: str):
|
419 |
+
def combine_cents(m: Match):
|
420 |
+
try:
|
421 |
+
currency = m.group(1)
|
422 |
+
integer = m.group(2)
|
423 |
+
cents = int(m.group(3))
|
424 |
+
return f"{currency}{integer}.{cents:02d}"
|
425 |
+
except ValueError:
|
426 |
+
return m.string
|
427 |
+
|
428 |
+
def extract_cents(m: Match):
|
429 |
+
try:
|
430 |
+
return f"¢{int(m.group(1))}"
|
431 |
+
except ValueError:
|
432 |
+
return m.string
|
433 |
+
|
434 |
+
# apply currency postprocessing; "$2 and ¢7" -> "$2.07"
|
435 |
+
s = re.sub(r"([€£$])([0-9]+) (?:and )?¢([0-9]{1,2})\b", combine_cents, s)
|
436 |
+
s = re.sub(r"[€£$]0.([0-9]{1,2})\b", extract_cents, s)
|
437 |
+
|
438 |
+
# write "one(s)" instead of "1(s)", just for the readability
|
439 |
+
s = re.sub(r"\b1(s?)\b", r"one\1", s)
|
440 |
+
|
441 |
+
return s
|
442 |
+
|
443 |
+
def __call__(self, s: str):
|
444 |
+
s = self.preprocess(s)
|
445 |
+
s = " ".join(word for word in self.process_words(s.split()) if word is not None)
|
446 |
+
s = self.postprocess(s)
|
447 |
+
|
448 |
+
return s
|
449 |
+
|
450 |
+
|
451 |
+
class EnglishReverseNumberNormalizer(EnglishNumberNormalizer):
|
452 |
+
"""
|
453 |
+
This is an approximate inverse of EnglishNumberNormalizer that converts arabic numerals
|
454 |
+
into spelled-out numbers.
|
455 |
+
|
456 |
+
Motivation: Whisper's original EnglishNumberNormalizer produces numberals that match Whisper's rich
|
457 |
+
token set, which many ASRs cannot output.
|
458 |
+
This class takes an alternative normalization approach, converting Whisper's numberals back to
|
459 |
+
spelled-out numbers. This ensures compatibility with the token sets of other ASR systems while
|
460 |
+
avoiding penalizing Whisper for outputting numerals.
|
461 |
+
|
462 |
+
Examples of cases handled:
|
463 |
+
- "365" -> "three hundred sixty five"
|
464 |
+
- "$20" -> "twenty dollars"
|
465 |
+
- "50%" -> "fifty percent"
|
466 |
+
- "12th" -> "twelfth", "12s" -> "twelves"
|
467 |
+
- "90th" -> "ninetieth", "90s" -> "nineties"
|
468 |
+
- The special cases of "70 000" -> "seventy thousand" but not larger numbers.
|
469 |
+
|
470 |
+
Caveats: this class takes care of the majority of cases, but it is not perfect.
|
471 |
+
- Only numerals within the 0-1000 range are handled.
|
472 |
+
- Minus/plus signs are not handled.
|
473 |
+
- There is inherent ambiguity e.g. "100" -> "one hundred" or "a hundred".
|
474 |
+
"""
|
475 |
+
|
476 |
+
def __init__(self):
|
477 |
+
super().__init__()
|
478 |
+
# Reverse dictionaries
|
479 |
+
self.int_to_ones = {v: k for k, v in self.ones.items()}
|
480 |
+
self.int_to_tens = {v: k for k, v in self.tens.items()}
|
481 |
+
|
482 |
+
# 11th -> eleventh etc.
|
483 |
+
self.str_to_ones_suffixed = {str(n)+s: k for k, (n,s) in self.ones_suffixed.items()}
|
484 |
+
# 20s -> twenties etc.
|
485 |
+
self.str_to_tens_suffixed = {str(n)+s: k for k, (n,s) in self.tens_suffixed.items()}
|
486 |
+
|
487 |
+
def __call__(self, s: str):
|
488 |
+
# "$x[.y]" -> "x[.y] dollars"
|
489 |
+
s = re.sub(r'\$(\d+(\.\d+)?)', r'\1 dollars', s)
|
490 |
+
# "x[.y]"% -> "x[.y] percent"
|
491 |
+
s = re.sub(r'(\d+(\.\d+)?)%', r'\1 percent', s)
|
492 |
+
# note this doesn't handle cases such as -x or +x.
|
493 |
+
|
494 |
+
def number_to_words(w: str):
|
495 |
+
if w.isdigit():
|
496 |
+
num = int(w)
|
497 |
+
if w == '000':
|
498 |
+
return 'thousand' # will work in case of "70 000" -> "seventy thousand"
|
499 |
+
if num == 0:
|
500 |
+
return "zero"
|
501 |
+
elif num == 100:
|
502 |
+
return "hundred"
|
503 |
+
elif 0 < num < 1000:
|
504 |
+
hundreds, remainder = divmod(num, 100)
|
505 |
+
tens, ones = divmod(remainder, 10)
|
506 |
+
h = [f"{self.int_to_ones[hundreds]} hundred"] if hundreds > 0 else []
|
507 |
+
if 0 < remainder <= 19:
|
508 |
+
t = [self.int_to_ones[remainder]]
|
509 |
+
o = []
|
510 |
+
else:
|
511 |
+
t = [self.int_to_tens[tens*10]] if tens > 0 else []
|
512 |
+
o = [self.int_to_ones[ones]] if ones > 0 else []
|
513 |
+
return " ".join(h + t + o)
|
514 |
+
elif num == 1000:
|
515 |
+
return "thousand"
|
516 |
+
else:
|
517 |
+
return w # case not handled
|
518 |
+
else:
|
519 |
+
# suffixed numbers
|
520 |
+
w = self.str_to_ones_suffixed.get(w, w)
|
521 |
+
w = self.str_to_tens_suffixed.get(w, w)
|
522 |
+
return w
|
523 |
+
|
524 |
+
return " ".join(number_to_words(w) for w in s.split())
|
525 |
+
|
526 |
+
|
527 |
+
class EnglishSpellingNormalizer:
|
528 |
+
"""
|
529 |
+
Applies British-American spelling mappings as listed in [1].
|
530 |
+
|
531 |
+
[1] https://www.tysto.com/uk-us-spelling-list.html
|
532 |
+
"""
|
533 |
+
|
534 |
+
def __init__(self, mapping_name="english.json"):
|
535 |
+
mapping_path = os.path.join(os.path.dirname(__file__), mapping_name)
|
536 |
+
self.mapping = json.load(open(mapping_path))
|
537 |
+
|
538 |
+
def __call__(self, s: str):
|
539 |
+
return " ".join(self.mapping.get(word, word) for word in s.split())
|
540 |
+
|
541 |
+
|
542 |
+
class EnglishTextNormalizer:
|
543 |
+
"""
|
544 |
+
This is a modified version of the Whisper text normalizer designed to enhance compatibility
|
545 |
+
across various ASRs.
|
546 |
+
|
547 |
+
Key features:
|
548 |
+
|
549 |
+
1. Idempotency: output is unchanged with repeated application.
|
550 |
+
2. The original Whisper-tailored number normalization is replaced with one that is compatible with
|
551 |
+
other ASR systems, mapping numerals into spelled-out numbers.
|
552 |
+
See EnglishReverseNumberNormalizer for details and limitations.
|
553 |
+
3. Filler words are removed by default, similar to the original normalizer: ['hmm', 'uh', 'ah', 'eh'].
|
554 |
+
This is for compatibility with ASRs trained to ignore these.
|
555 |
+
4. Added normalization for some common words: okay -> ok, everyday -> every day etc.
|
556 |
+
|
557 |
+
"""
|
558 |
+
def __init__(self, standardize_numbers=False, standardize_numbers_rev=True, remove_fillers=True):
|
559 |
+
self.replacers = {
|
560 |
+
# common non verbal sounds are mapped to the similar ones
|
561 |
+
r"\b(hm+)\b|\b(mhm)\b|\b(mm+)\b|\b(m+h)\b|\b(hm+)\b|\b(um+)\b|\b(uhm+)\b": ( # noqa e501
|
562 |
+
"hmm"
|
563 |
+
),
|
564 |
+
r"\b(a+h+)\b|\b(ha+)\b": "ah",
|
565 |
+
r"[!?.]+(?=$|\s)": "", # Okay.. --> okay
|
566 |
+
r"\b(o+h+)\b|\b(h+o+)\b": "oh",
|
567 |
+
r"\b(u+h+)\b|\b(h+u+)\b|\b(h+u+h+)\b": "uh",
|
568 |
+
# common contractions
|
569 |
+
r"\b(wi\sfi)\b": "wifi",
|
570 |
+
r"\b(goin)\b": "going",
|
571 |
+
r"\wi-fi\b": "wifi",
|
572 |
+
r"\bwon't\b": "will not",
|
573 |
+
r"\bcan't\b": "can not",
|
574 |
+
r"\blet's\b": "let us",
|
575 |
+
r"\bain't\b": "aint",
|
576 |
+
r"\by'all\b": "you all",
|
577 |
+
r"\bwanna\b": "want to",
|
578 |
+
r"\bgotta\b": "got to",
|
579 |
+
r"\bgonna\b": "going to",
|
580 |
+
r"\bi'ma\b": "i am going to",
|
581 |
+
r"\bimma\b": "i am going to",
|
582 |
+
r"\bwoulda\b": "would have",
|
583 |
+
r"\bcoulda\b": "could have",
|
584 |
+
r"\bshoulda\b": "should have",
|
585 |
+
r"\bma'am\b": "madam",
|
586 |
+
r"\bokay\b": "ok",
|
587 |
+
r"\bsetup\b": "set up",
|
588 |
+
r"\beveryday\b": "every day",
|
589 |
+
# contractions in titles/prefixes
|
590 |
+
r"\bmr\b": "mister ",
|
591 |
+
r"\bmrs\b": "missus ",
|
592 |
+
r"\bst\b": "saint ",
|
593 |
+
r"\bdr\b": "doctor ",
|
594 |
+
r"\bprof\b": "professor ",
|
595 |
+
r"\bcapt\b": "captain ",
|
596 |
+
r"\bgov\b": "governor ",
|
597 |
+
r"\bald\b": "alderman ",
|
598 |
+
r"\bgen\b": "general ",
|
599 |
+
r"\bsen\b": "senator ",
|
600 |
+
r"\brep\b": "representative ",
|
601 |
+
r"\bpres\b": "president ",
|
602 |
+
r"\brev\b": "reverend ",
|
603 |
+
r"\bhon\b": "honorable ",
|
604 |
+
r"\basst\b": "assistant ",
|
605 |
+
r"\bassoc\b": "associate ",
|
606 |
+
r"\blt\b": "lieutenant ",
|
607 |
+
r"\bcol\b": "colonel ",
|
608 |
+
r"\bjr\b": "junior ",
|
609 |
+
r"\bsr\b": "senior ",
|
610 |
+
r"\besq\b": "esquire ",
|
611 |
+
r"'d been\b": " had been",
|
612 |
+
r"'s been\b": " has been",
|
613 |
+
r"'d gone\b": " had gone",
|
614 |
+
r"'s gone\b": " has gone",
|
615 |
+
r"'d done\b": " had done",
|
616 |
+
r"'s got\b": " has got",
|
617 |
+
# general contractions
|
618 |
+
r"n't\b": " not",
|
619 |
+
r"'re\b": " are",
|
620 |
+
r"'s\b": " is",
|
621 |
+
r"'d\b": " would",
|
622 |
+
r"'ll\b": " will",
|
623 |
+
r"'t\b": " not",
|
624 |
+
r"'ve\b": " have",
|
625 |
+
r"'m\b": " am",
|
626 |
+
}
|
627 |
+
if standardize_numbers:
|
628 |
+
self.standardize_numbers = EnglishNumberNormalizer()
|
629 |
+
assert not standardize_numbers_rev
|
630 |
+
else:
|
631 |
+
self.standardize_numbers = None
|
632 |
+
|
633 |
+
if standardize_numbers_rev:
|
634 |
+
self.standardize_numbers_rev = EnglishReverseNumberNormalizer()
|
635 |
+
else:
|
636 |
+
self.standardize_numbers_rev = None
|
637 |
+
|
638 |
+
self.standardize_spellings = EnglishSpellingNormalizer()
|
639 |
+
self.pre_standardize_spellings = EnglishSpellingNormalizer("pre_english.json")
|
640 |
+
|
641 |
+
if remove_fillers:
|
642 |
+
self.fillers = ['hmm', 'uh', 'ah', 'eh'] # assumes replacers have been applied
|
643 |
+
else:
|
644 |
+
self.fillers = None
|
645 |
+
|
646 |
+
def __call__(self, s: str):
|
647 |
+
s = s.lower()
|
648 |
+
|
649 |
+
s = re.sub(r"[<\[][^>\]]*[>\]]", "", s)
|
650 |
+
# remove words between brackets
|
651 |
+
s = re.sub(r"\(([^)]+?)\)", "", s)
|
652 |
+
# remove words between parenthesis
|
653 |
+
s = self.pre_standardize_spellings(s)
|
654 |
+
s = re.sub(r"\s+'", "'", s)
|
655 |
+
# when there's a space before an apostrophe
|
656 |
+
|
657 |
+
for pattern, replacement in self.replacers.items():
|
658 |
+
s = re.sub(pattern, replacement, s)
|
659 |
+
|
660 |
+
s = re.sub(r"(\d),(\d)", r"\1\2", s)
|
661 |
+
# remove commas between digits
|
662 |
+
s = re.sub(r"\.([^0-9]|$)", r" \1", s)
|
663 |
+
# remove periods not followed by numbers
|
664 |
+
s = remove_symbols_and_diacritics(s, keep=".%$¢€£")
|
665 |
+
# keep numeric symbols
|
666 |
+
|
667 |
+
if self.standardize_numbers is not None:
|
668 |
+
s = self.standardize_numbers(s)
|
669 |
+
|
670 |
+
if self.standardize_numbers_rev is not None:
|
671 |
+
s = self.standardize_numbers_rev(s)
|
672 |
+
|
673 |
+
s = self.standardize_spellings(s)
|
674 |
+
# now remove prefix/suffix symbols
|
675 |
+
# that are not preceded/followed by numbers
|
676 |
+
s = re.sub(r"[.$¢€£]([^0-9])", r" \1", s)
|
677 |
+
s = re.sub(r"([^0-9])%", r"\1 ", s)
|
678 |
+
|
679 |
+
# remove filler words
|
680 |
+
# motivation: these words are very common, yet hold little information in the majority of cases.
|
681 |
+
# some ASR systems may ignore them by convention and will be penalized unfairly.
|
682 |
+
if self.fillers:
|
683 |
+
s = re.sub(r'\b(' + '|'.join(self.fillers) + r')\b', "", s)
|
684 |
+
|
685 |
+
s = re.sub(r"\s+", " ", s)
|
686 |
+
# replace any successive whitespaces with a space
|
687 |
+
|
688 |
+
s = re.sub(r"^\s+|\s+$", "", s)
|
689 |
+
# remove leading and trailing whitespaces
|
690 |
+
|
691 |
+
return s
|
txt_norm/pre_english.json
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"shan't": "shall not",
|
3 |
+
"han't": "has not",
|
4 |
+
"ain't": "ain not"
|
5 |
+
}
|
utils.py
ADDED
@@ -0,0 +1,282 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import logging
|
3 |
+
import os
|
4 |
+
from collections import OrderedDict
|
5 |
+
from decimal import Decimal
|
6 |
+
from pathlib import Path
|
7 |
+
from typing import Callable, Union
|
8 |
+
from typing import Tuple, Optional, List, Dict
|
9 |
+
|
10 |
+
import meeteval
|
11 |
+
import numpy as np
|
12 |
+
import pandas as pd
|
13 |
+
from meeteval.io.seglst import SegLstSegment
|
14 |
+
from meeteval.wer.wer.orc import OrcErrorRate
|
15 |
+
|
16 |
+
# this must be called before any other loggers are instantiated to take effect
|
17 |
+
logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] [%(name)s] %(message)s')
|
18 |
+
|
19 |
+
|
20 |
+
def get_logger(name: str):
|
21 |
+
"""
|
22 |
+
All modules should use this function to get a logger.
|
23 |
+
This way, we ensure all loggers are instantiated after basicConfig() call and inherit the same config.
|
24 |
+
"""
|
25 |
+
return logging.getLogger(name)
|
26 |
+
|
27 |
+
|
28 |
+
_LOG = get_logger('wer')
|
29 |
+
|
30 |
+
|
31 |
+
def create_dummy_seg_list(session_id):
|
32 |
+
return meeteval.io.SegLST(
|
33 |
+
[{'session_id': session_id, 'start_time': Decimal(0), 'end_time': Decimal(0), 'speaker': '', 'words': ''}])
|
34 |
+
|
35 |
+
|
36 |
+
def calc_session_tcp_wer(ref, hyp, collar):
|
37 |
+
res = meeteval.wer.tcpwer(reference=ref, hypothesis=hyp, collar=collar)
|
38 |
+
|
39 |
+
res_df = pd.DataFrame.from_dict(res, orient='index').reset_index(names='session_id')
|
40 |
+
keys = ['error_rate', 'errors', 'length', 'insertions', 'deletions', 'substitutions',
|
41 |
+
'missed_speaker', 'falarm_speaker', 'scored_speaker', 'assignment']
|
42 |
+
return (res_df[['session_id'] + keys]
|
43 |
+
.rename(columns={k: 'tcp_' + k for k in keys})
|
44 |
+
.rename(columns={'tcp_error_rate': 'tcp_wer'}))
|
45 |
+
|
46 |
+
|
47 |
+
def calc_wer(
|
48 |
+
ref_seglst: SegLstSegment,
|
49 |
+
tcp_hyp_seglst: SegLstSegment,
|
50 |
+
collar: int = 5,
|
51 |
+
metrics_list: List[str] = None) -> pd.DataFrame:
|
52 |
+
"""
|
53 |
+
Calculates tcpWER and tcorcWER for each session in hypothesis files using meeteval, and saves the error
|
54 |
+
information to .json.
|
55 |
+
Text normalization is applied to both hypothesis and reference.
|
56 |
+
|
57 |
+
Args:
|
58 |
+
out_dir: the directory to save the ref.json reference transcript to (extracted from gt_utt_df).
|
59 |
+
tcp_wer_hyp_json: path to hypothesis .json file for tcpWER, or json structure.
|
60 |
+
tcorc_wer_hyp_json: path to hypothesis .json file for tcorcWER, or json structure.
|
61 |
+
gt_utt_df: dataframe of ground truth utterances. must include the sessions in the hypothesis files.
|
62 |
+
see load_data() function.
|
63 |
+
tn: text normalizer
|
64 |
+
collar: tolerance of tcpWER to temporal misalignment between hypothesis and reference.
|
65 |
+
save_visualizations: if True, save html visualizations of alignment between hyp and ref.
|
66 |
+
meeting_id_is_session_id: if True, the session_id in the hypothesis/ref files is the same as the meeting_id.
|
67 |
+
Returns:
|
68 |
+
wer_df: pd.DataFrame with columns -
|
69 |
+
'session_id' - same as in hypothesis files
|
70 |
+
'tcp_wer': tcpWER
|
71 |
+
'tcorc_wer': tcorcWER
|
72 |
+
... intermediate tcpWER/tcorcWER fields such as insertions/deletions. see in code.
|
73 |
+
"""
|
74 |
+
# json to SegLST structure (Segment-wise Long-form Speech Transcription annotation)
|
75 |
+
if len(tcp_hyp_seglst) == 0:
|
76 |
+
tcp_hyp_seglst = create_dummy_seg_list(ref_seglst.segments[0]['session_id'])
|
77 |
+
_LOG.warning(f"Empty tcp_wer_hyp_json, using dummy segment: {tcp_hyp_seglst.segments[0]}")
|
78 |
+
|
79 |
+
wers_to_concat = []
|
80 |
+
|
81 |
+
if "tcp_wer" in metrics_list:
|
82 |
+
tcp_wer_res = calc_session_tcp_wer(ref_seglst, tcp_hyp_seglst, collar)
|
83 |
+
wers_to_concat.append(tcp_wer_res.drop(columns='session_id'))
|
84 |
+
|
85 |
+
wer_df = pd.concat(wers_to_concat, axis=1)
|
86 |
+
|
87 |
+
wer_df['session_id'] = ref_seglst.segments[0]['session_id']
|
88 |
+
_LOG.debug('Done calculating WER')
|
89 |
+
|
90 |
+
_LOG.debug(f"\n{wer_df[['session_id', *metrics_list]]}")
|
91 |
+
|
92 |
+
return wer_df
|
93 |
+
|
94 |
+
def aggregate_wer_metrics(wer_df: pd.DataFrame, metrics_list: List[str]) -> Dict:
|
95 |
+
num_wer_df = wer_df._get_numeric_data()
|
96 |
+
metrics = num_wer_df.sum().to_dict(into=OrderedDict)
|
97 |
+
|
98 |
+
for metric in metrics_list:
|
99 |
+
mprefix, _ = metric.split("_", maxsplit=1)
|
100 |
+
metrics[mprefix + "_wer"] = metrics[mprefix + "_errors"] / metrics[mprefix + "_length"]
|
101 |
+
for k in ['missed_speaker', 'falarm_speaker', 'scored_speaker']:
|
102 |
+
# compute mean for this keys
|
103 |
+
key = f"{mprefix}_{k}"
|
104 |
+
new_key = f"{mprefix}_mean_{k}"
|
105 |
+
if key not in metrics:
|
106 |
+
continue
|
107 |
+
metrics[new_key] = metrics[key] / len(num_wer_df)
|
108 |
+
del metrics[key]
|
109 |
+
return metrics
|
110 |
+
|
111 |
+
def normalize_segment(segment: SegLstSegment, tn):
|
112 |
+
words = segment["words"]
|
113 |
+
words = tn(words)
|
114 |
+
segment["words"] = words
|
115 |
+
return segment
|
116 |
+
|
117 |
+
|
118 |
+
def assign_streams(tcorc_hyp_seglst):
|
119 |
+
tcorc_hyp_seglst = tcorc_hyp_seglst.groupby(key='speaker')
|
120 |
+
per_stream_list = [[] for _ in range(len(tcorc_hyp_seglst))]
|
121 |
+
for speaker_id, speaker_seglst in tcorc_hyp_seglst.items():
|
122 |
+
speaker_seglst = speaker_seglst.sorted(key='start_time')
|
123 |
+
for seg in speaker_seglst:
|
124 |
+
# check if current segment does not overlap with any of the segments in per_stream_list
|
125 |
+
for i in range(len(per_stream_list)):
|
126 |
+
if not any(seg['start_time'] < s['end_time'] and seg['end_time'] > s['start_time'] for s in
|
127 |
+
per_stream_list[i]):
|
128 |
+
seg['speaker'] = i
|
129 |
+
per_stream_list[i].append(seg)
|
130 |
+
break
|
131 |
+
else:
|
132 |
+
raise ValueError('No stream found for segment')
|
133 |
+
tcorc_hyp_seglst = meeteval.io.SegLST([seg for stream in per_stream_list for seg in stream]).sorted(
|
134 |
+
key='start_time')
|
135 |
+
return tcorc_hyp_seglst
|
136 |
+
|
137 |
+
|
138 |
+
def filter_empty_segments(seg_lst):
|
139 |
+
return seg_lst.filter(lambda seg: seg['words'] != '')
|
140 |
+
|
141 |
+
|
142 |
+
def find_first_non_overlapping_segment_streams(per_speaker_groups, per_speaker_vad_masks):
|
143 |
+
for speaker_id, speaker_seglst in per_speaker_groups.items():
|
144 |
+
for other_speaker_id, other_speaker_seglst in per_speaker_groups.items():
|
145 |
+
if speaker_id != other_speaker_id:
|
146 |
+
vad_mask_merged = per_speaker_vad_masks[speaker_id] & per_speaker_vad_masks[other_speaker_id]
|
147 |
+
if not vad_mask_merged.any():
|
148 |
+
return (speaker_id, other_speaker_id)
|
149 |
+
|
150 |
+
|
151 |
+
def change_speaker_id(segment, speaker_id):
|
152 |
+
segment['speaker'] = speaker_id
|
153 |
+
return segment
|
154 |
+
|
155 |
+
|
156 |
+
def merge_streams(tcorc_hyp_seglst):
|
157 |
+
per_speaker_groups = tcorc_hyp_seglst.groupby(key='speaker')
|
158 |
+
|
159 |
+
# create per speaker vad masks
|
160 |
+
per_speaker_vad_masks = {}
|
161 |
+
for speaker_id, speaker_seglst in per_speaker_groups.items():
|
162 |
+
per_speaker_vad_masks[speaker_id] = create_vad_mask(speaker_seglst, time_step=0.01)
|
163 |
+
|
164 |
+
longest_mask = max(len(mask) for mask in per_speaker_vad_masks.values())
|
165 |
+
|
166 |
+
# pad all masks to the same length
|
167 |
+
for speaker_id, mask in per_speaker_vad_masks.items():
|
168 |
+
per_speaker_vad_masks[speaker_id] = np.pad(mask, (0, longest_mask - len(mask)))
|
169 |
+
|
170 |
+
# recursively merge all pairs of speakers that have no overlapping vad masks
|
171 |
+
while True:
|
172 |
+
res = find_first_non_overlapping_segment_streams(per_speaker_groups, per_speaker_vad_masks)
|
173 |
+
if res is None:
|
174 |
+
break
|
175 |
+
speaker_id, other_speaker_id = res
|
176 |
+
per_speaker_groups[speaker_id] = per_speaker_groups[speaker_id] + per_speaker_groups[other_speaker_id].map(
|
177 |
+
lambda seg: change_speaker_id(seg, speaker_id))
|
178 |
+
per_speaker_vad_masks[speaker_id] = per_speaker_vad_masks[speaker_id] | per_speaker_vad_masks[other_speaker_id]
|
179 |
+
del per_speaker_groups[other_speaker_id]
|
180 |
+
del per_speaker_vad_masks[other_speaker_id]
|
181 |
+
|
182 |
+
tcorc_hyp_seglst = meeteval.io.SegLST(
|
183 |
+
[seg for speaker_seglst in per_speaker_groups.values() for seg in speaker_seglst]).sorted(key='start_time')
|
184 |
+
|
185 |
+
return tcorc_hyp_seglst
|
186 |
+
|
187 |
+
|
188 |
+
def normalize_segment(segment: SegLstSegment, tn):
|
189 |
+
words = segment["words"]
|
190 |
+
words = tn(words)
|
191 |
+
segment["words"] = words
|
192 |
+
return segment
|
193 |
+
|
194 |
+
|
195 |
+
def create_vad_mask(segments, time_step=0.1, total_duration=None):
|
196 |
+
"""
|
197 |
+
Create a VAD mask for the given segments.
|
198 |
+
|
199 |
+
:param segments: List of segments, each containing 'start_time' and 'end_time'
|
200 |
+
:param time_step: The resolution of the VAD mask in seconds (default: 100ms)
|
201 |
+
:param total_duration: Optionally specify the total duration to create the mask.
|
202 |
+
If not provided, the mask will be generated based on the maximum end time of the segments.
|
203 |
+
:return: VAD mask as a numpy array, where 1 represents voice activity and 0 represents silence.
|
204 |
+
"""
|
205 |
+
# Find the total duration if not provided
|
206 |
+
if total_duration is None:
|
207 |
+
total_duration = max(seg['end_time'] for seg in segments)
|
208 |
+
|
209 |
+
# Initialize VAD mask as zeros (silence)
|
210 |
+
mask_length = int(float(total_duration) / time_step) + 1
|
211 |
+
vad_mask = np.zeros(mask_length, dtype=bool)
|
212 |
+
|
213 |
+
# Iterate over segments and mark the corresponding times as active (1)
|
214 |
+
for seg in segments:
|
215 |
+
start_idx = int(float(seg['start_time']) / time_step)
|
216 |
+
end_idx = int(float(seg['end_time']) / time_step)
|
217 |
+
vad_mask[start_idx:end_idx] = 1
|
218 |
+
|
219 |
+
return vad_mask
|
220 |
+
|
221 |
+
|
222 |
+
def find_group_splits(vad, group_duration=30, time_step=0.1):
|
223 |
+
non_active_indices = np.argwhere(~vad).squeeze(axis=-1)
|
224 |
+
splits = []
|
225 |
+
group_shift = group_duration / time_step
|
226 |
+
next_offset = group_shift
|
227 |
+
for i in non_active_indices:
|
228 |
+
if i >= next_offset:
|
229 |
+
splits.append(i)
|
230 |
+
next_offset = i + group_shift
|
231 |
+
return splits
|
232 |
+
|
233 |
+
|
234 |
+
def map_utterance_to_split(utterance_start_time, splits):
|
235 |
+
for i, split in enumerate(splits):
|
236 |
+
if utterance_start_time < split:
|
237 |
+
return i
|
238 |
+
return len(splits)
|
239 |
+
|
240 |
+
|
241 |
+
def agregate_errors_across_groups(res, session_id):
|
242 |
+
overall_error_number = sum([group.errors for group in res.values()])
|
243 |
+
overall_length = sum([group.length for group in res.values()])
|
244 |
+
overall_errors = {
|
245 |
+
'error_rate': overall_error_number / overall_length,
|
246 |
+
'errors': overall_error_number,
|
247 |
+
'length': overall_length,
|
248 |
+
'insertions': sum([group.insertions for group in res.values()]),
|
249 |
+
'deletions': sum([group.deletions for group in res.values()]),
|
250 |
+
'substitutions': sum([group.substitutions for group in res.values()]),
|
251 |
+
'assignment': []
|
252 |
+
}
|
253 |
+
for group in res.values():
|
254 |
+
overall_errors['assignment'].extend(list(group.assignment))
|
255 |
+
overall_errors['assignment'] = tuple(overall_errors['assignment'])
|
256 |
+
res = {session_id: OrcErrorRate(errors=overall_errors["errors"],
|
257 |
+
length=overall_errors["length"],
|
258 |
+
insertions=overall_errors["insertions"],
|
259 |
+
deletions=overall_errors["deletions"],
|
260 |
+
substitutions=overall_errors["substitutions"],
|
261 |
+
hypothesis_self_overlap=None,
|
262 |
+
reference_self_overlap=None,
|
263 |
+
assignment=overall_errors["assignment"])}
|
264 |
+
return res
|
265 |
+
|
266 |
+
|
267 |
+
def aggregate_wer_metrics(wer_df: pd.DataFrame, metrics_list: List[str]) -> Dict:
|
268 |
+
num_wer_df = wer_df._get_numeric_data()
|
269 |
+
metrics = num_wer_df.sum().to_dict(into=OrderedDict)
|
270 |
+
|
271 |
+
for metric in metrics_list:
|
272 |
+
mprefix, _ = metric.split("_", maxsplit=1)
|
273 |
+
metrics[mprefix + "_wer"] = metrics[mprefix + "_errors"] / metrics[mprefix + "_length"]
|
274 |
+
for k in ['missed_speaker', 'falarm_speaker', 'scored_speaker']:
|
275 |
+
# compute mean for this keys
|
276 |
+
key = f"{mprefix}_{k}"
|
277 |
+
new_key = f"{mprefix}_mean_{k}"
|
278 |
+
if key not in metrics:
|
279 |
+
continue
|
280 |
+
metrics[new_key] = metrics[key] / len(num_wer_df)
|
281 |
+
del metrics[key]
|
282 |
+
return metrics
|