@@ -70,7 +70,7 @@ fn find_valid_number_with_suffix(s: &str, unit: Unit) -> Option<&str> {
7070 }
7171}
7272
73- fn detailed_error_message ( s : & str , unit : Unit ) -> Option < String > {
73+ fn detailed_error_message ( s : & str , unit : Unit , unit_separator : & str ) -> Option < String > {
7474 if s. is_empty ( ) {
7575 return Some ( translate ! ( "numfmt-error-invalid-number-empty" ) ) ;
7676 }
@@ -87,6 +87,41 @@ fn detailed_error_message(s: &str, unit: Unit) -> Option<String> {
8787 return Some ( translate ! ( "numfmt-error-invalid-number" , "input" => s. quote( ) ) ) ;
8888 }
8989
90+ // When a unit separator is in use, the valid part may extend beyond the
91+ // contiguous number+suffix found by find_valid_number_with_suffix.
92+ // For example "5 K Field2" with unit_separator=" " has valid_part="5" but
93+ // the real valid prefix is "5 K"; the trailing " Field2" is the garbage.
94+ let valid_end =
95+ if !unit_separator. is_empty ( ) && valid_part == find_numeric_beginning ( s) . unwrap_or ( "" ) {
96+ let rest = & s[ valid_part. len ( ) ..] ;
97+ if let Some ( after_sep) = rest. strip_prefix ( unit_separator) {
98+ // Check if the next char is a valid suffix letter
99+ let mut chars = after_sep. chars ( ) ;
100+ let has_suffix = chars
101+ . next ( )
102+ . is_some_and ( |c| RawSuffix :: try_from ( & c) . is_ok ( ) ) ;
103+ if has_suffix {
104+ let suffix_char_len = 1 ;
105+ let with_i =
106+ chars. next ( ) == Some ( 'i' ) && [ Unit :: Auto , Unit :: Iec ( true ) ] . contains ( & unit) ;
107+ let suffix_len = if with_i {
108+ suffix_char_len + 1
109+ } else {
110+ suffix_char_len
111+ } ;
112+ valid_part. len ( ) + unit_separator. len ( ) + suffix_len
113+ } else {
114+ valid_part. len ( )
115+ }
116+ } else {
117+ valid_part. len ( )
118+ }
119+ } else {
120+ valid_part. len ( )
121+ } ;
122+
123+ let valid_part = & s[ ..valid_end] ;
124+
90125 if valid_part != s && valid_part. parse :: < f64 > ( ) . is_ok ( ) {
91126 return match s. chars ( ) . nth ( valid_part. len ( ) ) {
92127 Some ( '+' | '-' ) => {
@@ -100,9 +135,10 @@ fn detailed_error_message(s: &str, unit: Unit) -> Option<String> {
100135 } ;
101136 }
102137
103- if valid_part != s && valid_part. parse :: < f64 > ( ) . is_err ( ) {
138+ if valid_part != s {
139+ let trailing = s[ valid_part. len ( ) ..] . trim_start ( ) ;
104140 return Some (
105- translate ! ( "numfmt-error-invalid-specific-suffix" , "input" => s. quote( ) , "suffix" => s [ valid_part . len ( ) .. ] . quote( ) ) ,
141+ translate ! ( "numfmt-error-invalid-specific-suffix" , "input" => s. quote( ) , "suffix" => trailing . quote( ) ) ,
106142 ) ;
107143 }
108144 None
@@ -367,7 +403,9 @@ fn transform_from(s: &str, opts: &TransformOptions, options: &NumfmtOptions) ->
367403 & options. unit_separator ,
368404 options. explicit_unit_separator ,
369405 )
370- . map_err ( |original| detailed_error_message ( s, opts. from ) . unwrap_or ( original) ) ?;
406+ . map_err ( |original| {
407+ detailed_error_message ( s, opts. from , & options. unit_separator ) . unwrap_or ( original)
408+ } ) ?;
371409 let i = i * ( opts. from_unit as f64 ) ;
372410
373411 remove_suffix ( i, suffix, opts. from ) . map ( |n| {
@@ -818,20 +856,20 @@ mod tests {
818856
819857 #[ test]
820858 fn test_detailed_error_message ( ) {
821- let result = detailed_error_message ( "123i" , Unit :: Auto ) ;
859+ let result = detailed_error_message ( "123i" , Unit :: Auto , "" ) ;
822860 assert ! ( result. is_some( ) ) ;
823861 let error = result. unwrap ( ) ;
824862 assert ! ( error. contains( "numfmt-error-invalid-suffix" ) || error. contains( "invalid suffix" ) ) ;
825863
826- let result = detailed_error_message ( "5MF" , Unit :: Auto ) ;
864+ let result = detailed_error_message ( "5MF" , Unit :: Auto , "" ) ;
827865 assert ! ( result. is_some( ) ) ;
828866 let error = result. unwrap ( ) ;
829867 assert ! (
830868 error. contains( "numfmt-error-invalid-specific-suffix" )
831869 || error. contains( "invalid suffix" )
832870 ) ;
833871
834- let result = detailed_error_message ( "5KM" , Unit :: Auto ) ;
872+ let result = detailed_error_message ( "5KM" , Unit :: Auto , "" ) ;
835873 assert ! ( result. is_some( ) ) ;
836874 let error = result. unwrap ( ) ;
837875 assert ! (
0 commit comments