swift - stringbyaddingpercentencodingwithallowedcharacters - ¿Por qué el valor de retorno de String.addingPercentEncoding() es opcional?
cocoa unicode (2)
Basado en la respuesta de Paul Cantrell, pequeña demostración de que también es posible que el mismo método también devuelva nulo en Objective-C, a pesar de que String y NSString son diferentes bestias cuando se trata de codificaciones:
uint8_t bytes[2] = { 0xD8, 0x00 };
NSString *string = [[NSString alloc] initWithBytes:bytes length:2 encoding:NSUTF16BigEndianStringEncoding];
// /ud800
NSLog(@"%@", string);
NSString *escapedString = [string stringByAddingPercentEncodingWithAllowedCharacters:NSCharacterSet.URLHostAllowedCharacterSet];
// (null)
NSLog(@"%@", escapedString);
Por diversión, https://r12a.github.io/app-conversion/ escapará por ciento de la misma manera que:
Error% 20in% 20convertUTF162Char% 3A% 20low% 20surrogate% 20expected% 2C% 20b% 3D0% 21% 00
La firma del método String
para el porcentaje de escape es:
func addingPercentEncoding(withAllowedCharacters: CharacterSet)
-> String?
(Esto fue stringByAddingPercentEncodingWithAllowedCharacters
en Swift 2.)
¿Por qué este método devuelve un opcional?
La documentación dice que el método devuelve cero "si la transformación no es posible", pero no está claro en qué circunstancias podría fallar la transformación de escape:
Los caracteres se escapan utilizando UTF-8, que es una codificación Unicode completa. Cualquier carácter válido de Unicode puede codificarse utilizando UTF-8 y, por lo tanto, puede escaparse.
Pensé que tal vez el método aplicaba algún tipo de comprobación de validez para las malas interacciones entre el conjunto de caracteres permitidos y los caracteres utilizados para escapar, pero este no es el caso: el método tiene éxito, no importa si el conjunto de caracteres permitidos contiene "%", y también tiene éxito si el conjunto de caracteres permitido está vacío.
Tal como está, el valor de retorno no opcional parece estar forzando una comprobación de errores sin sentido.
Presenté un informe de error con Apple sobre esto, y escuché de nuevo, ¡con una respuesta muy útil, nada menos!
Resulta (para mi sorpresa) que es posible crear con éxito cadenas Swift que contengan Unicode no válido en forma de caracteres sustitutos UTF-16 no pareados. Una cadena de este tipo puede hacer que la codificación UTF-8 falle. Aquí hay un código que ilustra este comportamiento:
// Succeeds (wat?!):
let str = String(
bytes: [0xD8, 0x00] as [UInt8],
encoding: String.Encoding.utf16BigEndian)!
// Returns nil:
str.addingPercentEncoding(withAllowedCharacters:
CharacterSet.alphanumerics)