1#![feature(string_remove_matches, iter_intersperse)]
2
3#[macro_use]
4extern crate lazy_static;
5
6mod regex {
7 use regex::Regex;
8
9 const STR_TIMESTAMP_PATTERN: &str =
10 r"^(\d{2}):(\d{2}):(\d{2}),(\d{3})\s-->\s(\d{2}):(\d{2}):(\d{2}),(\d{3})$";
11 const STR_LINE_NUM_PATTERN: &str = r"^\d+$";
12
13 lazy_static! {
14 pub static ref SRT_TIMESTAMP_REGEX: Regex = Regex::new(STR_TIMESTAMP_PATTERN).unwrap();
15 pub static ref SRT_LINE_NUM_REGEX: Regex = Regex::new(STR_LINE_NUM_PATTERN).unwrap();
16 }
17
18 pub const PERSIAN_NUMBERS: [(char, &str); 10] = [
19 ('0', "۰"),
20 ('1', "۱"),
21 ('2', "۲"),
22 ('3', "۳"),
23 ('4', "۴"),
24 ('5', "۵"),
25 ('6', "۶"),
26 ('7', "۷"),
27 ('8', "۸"),
28 ('9', "۹"),
29 ];
30}
31
32pub struct Subtitle {
33 contents: String,
34}
35
36impl Subtitle {
37 pub fn new(contents: String) -> Self {
38 Self { contents }
39 }
40
41 pub fn fix(mut self) -> String {
42 self.remove_italics();
43 self.replace_arabic_chars();
44 self.replace_question_mark();
45 self.remove_rtl_char();
46 self.fix_others();
47 self.contents
48 }
49
50 fn remove_italics(&mut self) {
51 self.contents.remove_matches("<i>");
52 self.contents.remove_matches("</i>");
53 }
54
55 fn replace_arabic_chars(&mut self) {
56 self.contents = self.contents.replace('ي', "ی");
57 self.contents = self.contents.replace('ك', "ک");
58 }
59
60 fn replace_question_mark(&mut self) {
61 self.contents = self.contents.replace('?', "؟");
62 }
63
64 fn remove_rtl_char(&mut self) {
65 self.contents.remove_matches('\u{202b}');
66 }
67
68 fn fix_others(&mut self) {
69 let fix_line = |line: &str| {
70 match line {
71 l if regex::SRT_TIMESTAMP_REGEX.is_match(l) => l.into(),
72 l if l.trim().is_empty() => l.into(),
73 l if regex::SRT_LINE_NUM_REGEX.is_match(l) => l.into(),
74
75 l => {
77 let mut l = l.to_string();
81 for (n, p) in regex::PERSIAN_NUMBERS.into_iter() {
82 l = l.replace(n, p);
83 }
84
85 l
89 }
90 }
91 };
92
93 let contents = self
94 .contents
95 .lines()
96 .map(fix_line)
97 .intersperse("\n".to_owned())
98 .collect::<String>();
99 self.contents = contents;
100 }
101}
102
103#[cfg(test)]
104mod tests {
105 use crate::Subtitle;
106
107 #[test]
108 fn will_remove_italics() {
109 let input = r#"1
11000:08:26,025 --> 00:08:30,091
111<i>!زود باشین برین</i>
112
113!نمیذارم هیچ کدومتون اینجا بمیرین
114
1152
11600:08:22,037 --> 00:08:24,008
117!همه عجله کنین"#;
118
119 let expected = r#"1
12000:08:26,025 --> 00:08:30,091
121!زود باشین برین
122
123!نمیذارم هیچ کدومتون اینجا بمیرین
124
1252
12600:08:22,037 --> 00:08:24,008
127!همه عجله کنین"#;
128
129 let output = Subtitle::new(input.to_string()).fix();
130
131 assert_eq!(expected, output)
132 }
133
134 #[test]
135 fn will_replace_arabic_chars() {
136 let input = r#"1
13700:08:26,025 --> 00:08:30,091
138!زود باشین برين
139
140!نمیذارم هیچ كدومتون اینجا بمیرین
141
1422
14300:08:22,037 --> 00:08:24,008
144!همه عجله کنین"#;
145
146 let expected = r#"1
14700:08:26,025 --> 00:08:30,091
148!زود باشین برین
149
150!نمیذارم هیچ کدومتون اینجا بمیرین
151
1522
15300:08:22,037 --> 00:08:24,008
154!همه عجله کنین"#;
155
156 let output = Subtitle::new(input.to_string()).fix();
157
158 assert_eq!(expected, output)
159 }
160
161 #[test]
162 fn will_replace_question_mark() {
163 let input = r#"1
16400:08:26,025 --> 00:08:30,091
165؟زود باشین برين
166
167?نمیذارم هیچ كدومتون اینجا بمیرین
168
1692
17000:08:22,037 --> 00:08:24,008
171!همه عجله کنین"#;
172
173 let expected = r#"1
17400:08:26,025 --> 00:08:30,091
175؟زود باشین برین
176
177؟نمیذارم هیچ کدومتون اینجا بمیرین
178
1792
18000:08:22,037 --> 00:08:24,008
181!همه عجله کنین"#;
182
183 let output = Subtitle::new(input.to_string()).fix();
184
185 assert_eq!(expected, output)
186 }
187
188 #[test]
189 fn will_replace_numbers_with_persian_numbers() {
190 let input = r#"1
19100:08:26,025 --> 00:08:30,091
192؟زود باشین برين 12
193
194؟نمیذارم 2 هیچ كدومتون 0912 اینجا بمیرین
195
1962
19700:08:22,037 --> 00:08:24,008
198!همه 34عجله کنین"#;
199
200 let expected = r#"1
20100:08:26,025 --> 00:08:30,091
202؟زود باشین برین ۱۲
203
204؟نمیذارم ۲ هیچ کدومتون ۰۹۱۲ اینجا بمیرین
205
2062
20700:08:22,037 --> 00:08:24,008
208!همه ۳۴عجله کنین"#;
209
210 let output = Subtitle::new(input.to_string()).fix();
211
212 assert_eq!(expected, output)
213 }
214}