Skip to content

Commit 13dfa71

Browse files
committed
Fix typographic quotes algorithm
1 parent fcbe673 commit 13dfa71

File tree

1 file changed

+21
-16
lines changed

1 file changed

+21
-16
lines changed

Diff for: src/clean.rs

+21-16
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,8 @@ pub fn typographic_quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
6464
/// Custom whitespace-detection function, including `,`, `;`, `.`, `!`, `?`, and `:`
6565
fn is_whitespace(c: char) -> bool {
6666
match c {
67-
',' | '.' | ';' | '!' | '?' | ':' => true,
67+
',' | '.' | ';' | '!' | '?' | ':' | '"'
68+
| '(' | ')' => true,
6869
_ => c.is_whitespace()
6970
}
7071
}
@@ -83,27 +84,32 @@ pub fn typographic_quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
8384
}
8485
new_s.push_str(&input[0..first]);
8586
let chars = input[first..].chars().collect::<Vec<_>>();
86-
let mut has_opened_quote = false;
87+
let mut closing_quote = None;
8788
for i in 0..chars.len() {
8889
let c = chars[i];
90+
let has_opened_quote = if let Some(n) = closing_quote {
91+
i <= n
92+
} else {
93+
false
94+
};
8995
match c {
9096
'"' => {
91-
if i > 0 && !is_whitespace(chars[i - 1]) {
97+
if i > 0 && !chars[i-1].is_whitespace() {
9298
new_s.push('”');
93-
} else if i < chars.len() - 1 && !is_whitespace(chars[i + 1]) {
99+
} else if i < chars.len() - 1 && !is_whitespace(chars[i+1]) {
94100
new_s.push('“');
95101
} else {
96102
new_s.push('"');
97103
}
98104
},
99105
'\'' => {
100106
let prev = if i > 0 {
101-
Some(!is_whitespace(chars[i - 1]))
107+
Some(!chars[i - 1].is_whitespace())
102108
} else {
103109
None
104110
};
105111
let next = if i < chars.len() - 1 {
106-
Some(!is_whitespace(chars[i + 1]))
112+
Some(!chars[i+1].is_whitespace())
107113
} else {
108114
None
109115
};
@@ -118,26 +124,19 @@ pub fn typographic_quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
118124
let mut is_next_closing = false;
119125
for j in (i + 1)..chars.len() {
120126
if chars[j] == '\'' {
121-
println!("match at {}", j);
122127
if chars[j-1].is_whitespace() {
123-
println!("prev is whitespace, not closing quote");
124128
continue;
125129
} else {
126130
if j >= chars.len() - 1
127-
|| is_whitespace(chars[j+1])
128-
|| chars[j+1] == '"' {
131+
|| is_whitespace(chars[j+1]) {
129132
is_next_closing = true;
133+
closing_quote = Some(j);
130134
break;
131135
}
132-
else {
133-
println!("j: {}, len: {}", j, chars.len());
134-
}
135136
}
136137
}
137138
}
138-
println!("is_next_closing: {}", is_next_closing);
139139
if is_next_closing && !has_opened_quote {
140-
has_opened_quote = true;
141140
'‘'
142141
} else {
143142
'’'
@@ -148,7 +147,6 @@ pub fn typographic_quotes<'a, S: Into<Cow<'a, str>>>(input: S) -> Cow<'a, str> {
148147
(Some(true), Some(false))
149148
| (Some(true), None)
150149
=> {
151-
has_opened_quote = false;
152150
'’'
153151
},
154152

@@ -230,3 +228,10 @@ fn typographic_quotes_8() {
230228
let s = typographic_quotes("\"I like 'That '70s show'\", she said");
231229
assert_eq!(&s, "“I like ‘That ’70s show’”, she said");
232230
}
231+
232+
233+
#[test]
234+
fn typographic_quotes_9() {
235+
let s = typographic_quotes("some char: '!', '?', ','");
236+
assert_eq!(&s, "some char: ‘!’, ‘?’, ‘,’");
237+
}

0 commit comments

Comments
 (0)