@@ -318,16 +318,36 @@ impl PyString {
318318 formatted. push ( '\\' ) ;
319319 formatted. push ( c) ;
320320 } else if c == '\n' {
321- formatted. push ( '\\' ) ;
322- formatted. push ( 'n' ) ;
321+ formatted. push_str ( "\\ n" )
323322 } else if c == '\t' {
324- formatted. push ( '\\' ) ;
325- formatted. push ( 't' ) ;
323+ formatted. push_str ( "\\ t" ) ;
326324 } else if c == '\r' {
327- formatted. push ( '\\' ) ;
328- formatted. push ( 'r' ) ;
329- } else {
325+ formatted. push_str ( "\\ r" ) ;
326+ } else if c < ' ' || c as u32 == 0x7F {
327+ formatted. push_str ( & format ! ( "\\ x{:02x}" , c as u32 ) ) ;
328+ } else if c. is_ascii ( ) {
330329 formatted. push ( c) ;
330+ } else if c. is_other ( ) || c. is_separator ( ) {
331+ // According to python following categories aren't printable:
332+ // * Cc (Other, Control)
333+ // * Cf (Other, Format)
334+ // * Cs (Other, Surrogate)
335+ // * Co (Other, Private Use)
336+ // * Cn (Other, Not Assigned)
337+ // * Zl Separator, Line ('\u2028', LINE SEPARATOR)
338+ // * Zp Separator, Paragraph ('\u2029', PARAGRAPH SEPARATOR)
339+ // * Zs (Separator, Space) other than ASCII space('\x20').
340+ let code = c as u32 ;
341+ let escaped = if code < 0xff {
342+ format ! ( "\\ U{:02x}" , code)
343+ } else if code < 0xffff {
344+ format ! ( "\\ U{:04x}" , code)
345+ } else {
346+ format ! ( "\\ U{:08x}" , code)
347+ } ;
348+ formatted. push_str ( & escaped) ;
349+ } else {
350+ formatted. push ( c)
331351 }
332352 }
333353 formatted. push ( quote_char) ;
0 commit comments