@@ -292,11 +292,12 @@ impl Sequence {
292292 set2_uniques. sort_unstable ( ) ;
293293 set2_uniques. dedup ( ) ;
294294
295+ let set1_has_class = set1. iter ( ) . any ( |x| matches ! ( x, Self :: Class ( _) ) ) ;
295296 // If the complement flag is used in translate mode, only one unique
296297 // character may appear in set2. Validate this with the set of uniques
297298 // in set2 that we just generated.
298299 // Also, set2 must not overgrow set1, otherwise the mapping can't be 1:1.
299- if set1 . iter ( ) . any ( |x| matches ! ( x , Self :: Class ( _ ) ) )
300+ if set1_has_class
300301 && translating
301302 && complement_flag
302303 && ( set2_uniques. len ( ) > 1 || set2_solved. len ( ) > set1_len)
@@ -306,7 +307,23 @@ impl Sequence {
306307
307308 if set2_solved. len ( ) < set1_solved. len ( ) {
308309 if truncate_set1_flag {
309- set1_solved. truncate ( set2_solved. len ( ) ) ;
310+ if complement_flag && set1_has_class {
311+ // GNU applies -t before complementing a character class.
312+ // That means we must first truncate the expanded, non-complemented
313+ // source set, then complement the truncated prefix to recover the
314+ // final translation domain. Complementing first would incorrectly
315+ // shrink the complemented domain to the prefix length.
316+ let truncated_set1: Vec < _ > = set1
317+ . iter ( )
318+ . flat_map ( Self :: flatten)
319+ . take ( set2_solved. len ( ) )
320+ . collect ( ) ;
321+ set1_solved = ( 0 ..=u8:: MAX )
322+ . filter ( |x| !truncated_set1. contains ( x) )
323+ . collect ( ) ;
324+ } else {
325+ set1_solved. truncate ( set2_solved. len ( ) ) ;
326+ }
310327 } else if matches ! (
311328 set2. last( ) . copied( ) ,
312329 Some ( Self :: Class ( Class :: Upper | Class :: Lower ) )
0 commit comments