From 11d74134824e0c68a92cd6f603424aa6ec554983 Mon Sep 17 00:00:00 2001 From: kaanyalova <76952012+kaanyalova@users.noreply.github.com> Date: Wed, 30 Oct 2024 19:58:33 +0300 Subject: [PATCH 1/2] Fix inconsistencies with cpython while parsing format strings which contain colons inside square brackets --- format/src/format.rs | 81 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 8 deletions(-) diff --git a/format/src/format.rs b/format/src/format.rs index fd497b90..237fee50 100644 --- a/format/src/format.rs +++ b/format/src/format.rs @@ -863,17 +863,54 @@ impl FormatString { } fn parse_part_in_brackets(text: &str) -> Result { - let parts: Vec<&str> = text.splitn(2, ':').collect(); + let mut chars = text.chars().peekable(); + + let mut left = String::new(); + let mut right = String::new(); + + let mut split = false; + let mut inside_brackets = false; + + while let Some(char) = chars.next() { + if char == '[' { + inside_brackets = true; + + if split { + right.push(char); + } else { + left.push(char); + } + + while let Some(next_char) = chars.next() { + if split { + right.push(next_char); + } else { + left.push(next_char); + } + + if next_char == ']' { + inside_brackets = false; + break; + } + if chars.peek().is_none() { + return Err(FormatParseError::MissingRightBracket); + } + } + } else if char == ':' && !split && !inside_brackets { + split = true; + } else if split { + right.push(char); + } else { + left.push(char); + } + } + // before the comma is a keyword or arg index, after the comma is maybe a spec. - let arg_part = parts[0]; + let arg_part: &str = &left; - let format_spec = if parts.len() > 1 { - parts[1].to_owned() - } else { - String::new() - }; + let format_spec = if split { right } else { String::new() }; - // On parts[0] can still be the conversion (!r, !s, !a) + // left can still be the conversion (!r, !s, !a) let parts: Vec<&str> = arg_part.splitn(2, '!').collect(); // before the bang is a keyword or arg index, after the comma is maybe a conversion spec. let arg_part = parts[0]; @@ -1168,6 +1205,34 @@ mod tests { ); } + #[test] + fn test_square_brackets_inside_format() { + assert_eq!( + FormatString::from_str("{[:123]}"), + Ok(FormatString { + format_parts: vec![FormatPart::Field { + field_name: "[:123]".to_owned(), + conversion_spec: None, + format_spec: "".to_owned(), + }], + }), + ); + + assert_eq!(FormatString::from_str("{asdf[:123]asdf}"), { + Ok(FormatString { + format_parts: vec![FormatPart::Field { + field_name: "asdf[:123]asdf".to_owned(), + conversion_spec: None, + format_spec: "".to_owned(), + }], + }) + }); + + assert_eq!(FormatString::from_str("{[1234}"), { + Err(FormatParseError::MissingRightBracket) + }); + } + #[test] fn test_format_parse_escape() { let expected = Ok(FormatString { From 64723e1675f2533d498c7cfe47a08c3f1baa75e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kaan=20B=C3=BCy=C3=BCkerdem?= <76952012+kaanyalova@users.noreply.github.com> Date: Thu, 31 Oct 2024 10:33:14 +0300 Subject: [PATCH 2/2] Use selected for better readibility Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com> --- format/src/format.rs | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/format/src/format.rs b/format/src/format.rs index 237fee50..bc1bec28 100644 --- a/format/src/format.rs +++ b/format/src/format.rs @@ -869,24 +869,17 @@ impl FormatString { let mut right = String::new(); let mut split = false; + let mut selected = &mut left; let mut inside_brackets = false; while let Some(char) = chars.next() { if char == '[' { inside_brackets = true; - if split { - right.push(char); - } else { - left.push(char); - } + selected.push(char); while let Some(next_char) = chars.next() { - if split { - right.push(next_char); - } else { - left.push(next_char); - } + selected.push(next_char); if next_char == ']' { inside_brackets = false; @@ -898,10 +891,9 @@ impl FormatString { } } else if char == ':' && !split && !inside_brackets { split = true; - } else if split { - right.push(char); + selected = &mut right; } else { - left.push(char); + selected.push(char); } }