-
-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathtitle_normalization.py
More file actions
188 lines (172 loc) · 5.94 KB
/
Copy pathtitle_normalization.py
File metadata and controls
188 lines (172 loc) · 5.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
"""Code to attempt to get normalized movie titles for title matching, sorting etc"""
import re
import unicodedata
TITLE_REGEXES = [
r"^All out of bubblegum film club: *(.*)$",
r"^Bad Movie Night: (.*)$",
r"^Bar Trash: (.*)$",
r"^Brazilian Summer Nights: *(.*)$",
r"^CAMP CLASSICS presents: (.*)$",
r"^Carers & Babies: (.*)$",
r"^Category H: *(.*)$",
r"^Cine-real presents: (.*)$",
r"^Cinematix Escapes Presents: (.*)$",
r"^Classic Matinee: (.*)$",
r"^Dog friendly: (.*)$",
r"^Experiments in film: (.*)$",
r"^Exhibition on screen: (.*)$",
r"^Family film week: (.*)$",
r"^Family Films: (.*)$",
r"^Funeral Parade Presents '(.*)'$",
r"^Girls in Film: (.*)$",
r"^Hitchcock for Halloween: (.*)$",
r"^Japanese Film Club: *(.*)$",
r"^Member exclusive: (.*)$",
r"^Member Picks: (.*)$",
r"^Members' Screening: (.*)$",
r"^Outdoor Cinema: (.*)$",
r"^Parent & Baby: (.*)$",
r"^Parent & Baby Screening: (.*)$",
r"^Phoenix Classics: *(.*)$",
r"^Pink Palace: *(.*)$",
r"^Pitchblack Pictures: *(.*)$",
r"^Reborn India Film Presents:? *(.*)$",
r"^Relaxed Screening: (.*)$",
r"^Senior Community Screening: (.*)$",
r"^Seniors' Free Matinee: (.*)$",
r"^Seniors' Paid Matinee: (.*)$",
r"^Staff Selects: *(.*)$",
r"^UK Premiere:? *(.*)$",
r"^Sing-A-Long-A *(.*)$",
r"^[a-zA-Z ]+ Film Festival: *(.*)$",
r"^(.*) *\(UK Theatrical Premiere\)$",
r"^(.*) *\(Theatrical Cut\)$",
r"^(.*) *\[Theatrical Cut\]$",
r"^(.*) *\(Director'?s Cut\)$",
r"^(.*) *\[Director'?s Cut\]$",
r"^(.*) *\(4k restoration\)$",
r"^(.*) *4k restoration$",
r"^(.*) *\(4k restoration re[ -]?release\)$",
r"^(.*) *\+ Introduction$",
r"^(.*) *\+ introduction by .*$",
r"^(.*) *\+ intro$",
r"^(.*) *\+ intro by .*$",
r"^(.*) *plus intro by .*$",
r"^(.*) *with intro by .*$",
r"^(.*) *\+ pre-recorded intro by .*$",
r"^(.*) *\+ Panel discussion\b.*$",
r"^(.*) *plus Panel discussion\b.*$",
r"^(.*) *+ ScreenTalk$",
r"^(.*) *\+ Q&A\b.*$",
r"^(.*) *plus Q&A\b.*$",
r"^(.*) *\+ recorded Q&A\b.*$",
r"^(.*) *plus recorded Q&A\b.*$",
r"^(.*) *\+ director Q&A\b.*$",
r"^(.*) *plus director Q&A\b.*$",
r"^(.*) *\+ Live Organ$",
r"^(.*) \d\dst anniversary$",
r"^(.*) \d\dst anniversary edition$",
r"^(.*) \(\d\dst anniversary\)$",
r"^(.*) \(\d\dst anniversary 4K Restoration\)$",
r"^(.*) \[\d\dst anniversary\]$",
r"^(.*) *- *\d\dst anniversary$",
r"^(.*) \d\dth anniversary$",
r"^(.*) \d\dth anniversary edition$",
r"^(.*) \(\d\dth anniversary\)$",
r"^(.*) \(\d\d\dth anniversary\)$",
r"^(.*) \(\d\dth anniversary 4K Restoration\)$",
r"^(.*) \[\d\dth anniversary\]$",
r"^(.*) *- *\d\dth anniversary$",
r"^(.*) *\(Subtitled\) *$",
r"^(.*) *\[Subtitled\] *$",
r"^(.*) *\[English Subtitles\] *$",
r"^(.*) *\(English Subtitles\) *$",
r"^(.*) *\[SUBBED\] *$",
r"^(.*) *\[DUBBED\] *$",
r"^(.*) *\(DUBBED\) *$",
r"^(.*) *\[English language dub\] *$",
r"^(.*) *\[[a-zA-Z ]+ version\] *$",
r"^(.*) *\(2D\) *$",
r"^(.*) *\[2D\] *$",
r"^(.*) *\(3D\) *$",
r"^(.*) *\[3D\] *$",
r"^(.*) *Classics Presented in 35mm$",
r"^(.*) *\(IMAX\)",
r"^(.*) *\[IMAX\]",
r"^(.*) *- *The Chiswick Cinema$",
r"^(.*)$",
]
AMP_REGEX = re.compile(r" & ")
PUNC_REGEX = re.compile(r"[\.\!,:-]")
def normalize_quotes(text: str) -> str:
"""Convert curly/special apostrophes and quotes to straight ones."""
replacements = {
ord("‘"): "'",
ord("’"): "'",
ord("‚"): "'",
ord("‛"): "'",
ord("“"): '"',
ord("”"): '"',
ord("„"): '"',
ord("‟"): '"',
ord("‹"): "'",
ord("›"): "'",
ord("«"): '"',
ord("»"): '"',
}
return text.translate(replacements)
def normalize_dashes(text: str) -> str:
"""Convert various types of dashes to regular hyphens."""
replacements = {
ord("–"): "-", # en-dash
ord("—"): "-", # em-dash
ord("―"): "-", # horizontal bar
ord("‒"): "-", # figure dash
ord("−"): "-", # minus sign
}
return text.translate(replacements)
def normalize_accents(text: str) -> str:
"""Convert accented characters to their ASCII equivalents."""
# First handle common ligatures that NFD doesn't decompose
ligature_replacements = {
"æ": "ae",
"Æ": "AE",
"œ": "oe",
"Œ": "OE",
"ß": "ss",
"ẞ": "SS",
}
for ligature, replacement in ligature_replacements.items():
text = text.replace(ligature, replacement)
# Normalize to NFD (decomposed form) to separate base characters from combining marks
nfd = unicodedata.normalize("NFD", text)
# Filter out combining characters (accents, diacritics)
ascii_text = "".join(char for char in nfd if unicodedata.category(char) != "Mn")
return ascii_text
def run_regexes(title: str) -> str:
"""Run the title through the regexes to extract the normalized title."""
for regex in TITLE_REGEXES:
match = re.match(regex, title, re.I)
if match:
return match.group(1).strip()
raise RuntimeError(
"We shouldn't ever get here as the last regex should match anything."
)
def normalize_title(title: str) -> str:
title = title.strip().upper()
title = normalize_quotes(title)
title = normalize_dashes(title)
title = normalize_accents(title)
title = run_regexes(title)
# Run regexes a second time in case the title has both a prefix and a suffix
title = run_regexes(title)
if title:
title = PUNC_REGEX.sub(" ", title)
title = AMP_REGEX.sub(" AND ", title)
title = re.sub(r"\s+", " ", title)
title = title.strip()
assert title
return title
raise RuntimeError(
"We shouldn't ever get here as the last regex should match anything."
)