¿Es posible detectar enlaces dentro de una NSString que tienen espacios en ellos con NSDataDetector?
objective-c regex (8)
Acabo de recibir esta respuesta de Apple para un error que presenté al respecto:
Creemos que este problema se ha abordado en la última versión beta de iOS 9. Esta es una actualización de iOS 9 pre-lanzamiento.
Consulte las notas de la versión para obtener las instrucciones de instalación completas.
Por favor, prueba con esta versión. Si aún tiene problemas, proporcione registros o información relevante que pueda ayudarnos a investigar.
Probaré y les haré saber a todos si esto está arreglado con iOS 9.
En primer lugar, no tengo control sobre el texto que estoy recibiendo. Solo quería poner eso ahí para que sepas que no puedo cambiar los enlaces.
El texto que estoy tratando de encontrar enlaces en el uso de NSDataDetector
contiene lo siguiente:
<h1>My main item</h1>
<img src="http://www.blah.com/My First Image Here.jpg">
<h2>Some extra data</h2>
El código de detección que estoy usando es este, pero no encontrará este enlace:
NSDataDetector *linkDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeLink error:nil];
NSArray *matches = [linkDetector matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
for (NSTextCheckingResult *match in matches)
{
if ([match resultType] == NSTextCheckingTypeLink)
{
NSURL *url = [match URL];
// does some stuff
}
}
¿Se trata de un error en la detección de enlaces de Apple aquí, donde no puede detectar enlaces con espacios, o estoy haciendo algo mal?
¿Alguien tiene una forma más confiable de detectar enlaces sin importar si tienen espacios o caracteres especiales o lo que sea en ellos?
He encontrado una manera muy hacky para resolver mi problema. Si alguien encuentra una solución mejor que se pueda aplicar a todas las URL, por favor, hágalo.
Como solo me importan las URL que terminan en .jpg
que tienen este problema, pude encontrar una forma limitada de rastrear esto.
Esencialmente, separo la cadena en componentes basados en ellos comenzando con "http://
en una matriz. Luego hago un bucle a través de esa matriz haciendo otra ruptura buscando .jpg">
. El recuento de la matriz interna solo será > 1
cuando se encuentre la cadena .jpg">
. Luego mantengo tanto la cadena que encuentro como la cadena que corrijo con %20
reemplazos, y las uso para hacer una última cadena de reemplazo en la cadena original
No es perfecto y probablemente ineficiente, pero hace el trabajo para lo que necesito.
- (NSString *)replaceSpacesInJpegURLs:(NSString *)htmlString
{
NSString *newString = htmlString;
NSArray *array = [htmlString componentsSeparatedByString:@"/"http://"];
for (NSString *str in array)
{
NSArray *array2 = [str componentsSeparatedByString:@".jpg/""];
if ([array2 count] > 1)
{
NSString *stringToFix = [array2 objectAtIndex:0];
NSString *fixedString = [stringToFix stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
newString = [newString stringByReplacingOccurrencesOfString:stringToFix withString:fixedString];
}
}
return newString;
}
Las URL realmente no deberían contener espacios. Quitaría todos los espacios de la cadena antes de hacer cualquier cosa relacionada con la URL, algo como lo siguiente
// Custom function which cleans up strings ready to be used for URLs
func cleanStringForURL(string: NSString) -> NSString {
var temp = string
var clean = string.stringByReplacingOccurrencesOfString(" ", withString: "")
return clean
}
No debe utilizar NSDataDetector con HTML. Está destinado a analizar texto normal (introducido por un usuario), no datos generados por computadora (de hecho, tiene muchas heurísticas para asegurarse de que no detecte cosas generadas por computadora que probablemente no sean relevantes para el usuario).
Si su cadena es HTML, debe utilizar una biblioteca de análisis HTML. Hay una serie de kits de código abierto para ayudarte a hacerlo. Luego simplemente tome los atributos href de sus anclas, o ejecute NSDataDetector en los nodos de texto para encontrar cosas que no estén marcadas sin contaminar la cadena con etiquetas.
Prueba este fragmento (obtuve la expresión regular de tu primer comentarista usuario 3584460):
NSError *error = NULL;
NSString *myHTML = @"<http><h1>My main item</h1><img src=/"http://www.blah.com/My First Image Here.jpg/"><h2>Some extra data</h2><img src=/"http://www.bloh.com/My Second Image Here.jpg/"><h3>Some extra data</h3><img src=/"http://www.bluh.com/My Third-Image Here.jpg/"></http>";
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"src=[/"''](.+?)[/"''].*?>" options:NSRegularExpressionCaseInsensitive error:&error];
NSArray *arrayOfAllMatches = [regex matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
NSTextCheckingResult *match = [regex firstMatchInString:myHTML options:0 range:NSMakeRange(0, myHTML.length)];
for (NSTextCheckingResult *match in arrayOfAllMatches) {
NSRange range = [match rangeAtIndex:1];
NSString* substringForMatch = [myHTML substringWithRange:range];
NSLog(@"Extracted URL : %@",substringForMatch);
}
En mi registro, tengo:
Extracted URL : http://www.blah.com/My First Image Here.jpg
Extracted URL : http://www.bloh.com/My Second Image Here.jpg
Extracted URL : http://www.bluh.com/My Third-Image Here.jpg
Puede dividir las cadenas en pedazos utilizando los espacios para que tenga una serie de cadenas sin espacios. Luego, podría introducir cada una de esas cadenas en su detector de datos.
// assume str = <img src="http://www.blah.com/My First Image Here.jpg">
NSArray *components = [str componentsSeparatedByString:@" "];
for (NSString *strWithNoSpace in components) {
// feed strings into data detector
}
Otra alternativa es buscar específicamente esa etiqueta HTML. Sin embargo, esta es una solución menos genérica.
// assume that those 3 HTML strings are in a string array called strArray
for (NSString *htmlLine in strArray) {
if ([[htmlLine substringWithRange:NSMakeRange(0, 8)] isEqualToString:@"<img src"]) {
// Get the url from the img src tag
NSString *urlString = [htmlLine substringWithRange:NSMakeRange(10, htmlLine.length - 12)];
}
}
Puede usar NSRegularExpression
para corregir todas las URL utilizando una expresión regular simple para detectar los enlaces y luego codificar los espacios (si necesita una codificación más compleja, puede consultar CFURLCreateStringByAddingPercentEscapes
y hay muchos ejemplos). Lo único que podría llevarle algo de tiempo si no ha trabajado antes con NSRegularExpression
es cómo iterar los resultados y hacer el reemplazo, el siguiente código debería resolverlo:
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"src=/".*/"" options:NSRegularExpressionCaseInsensitive error:&error];
if (!error)
{
NSInteger offset = 0;
NSArray *matches = [regex matchesInString:myHTML options:0 range:NSMakeRange(0, [myHTML length])];
for (NSTextCheckingResult *result in matches)
{
NSRange resultRange = [result range];
resultRange.location += offset;
NSString *match = [regex replacementStringForResult:result inString:myHTML offset:offset template:@"$0"];
NSString *replacement = [match stringByReplacingOccurrencesOfString:@" " withString:@"%20"];
myHTML = [myHTML stringByReplacingCharactersInRange:resultRange withString:replacement];
offset += ([replacement length] - resultRange.length);
}
}
Pruebe este patrón de expresiones regulares: @"<img[^>]+src=(/"|'')([^/"'']+)(/"|'')[^>]*>"
con el caso de ignorar ... Índice de coincidencia = 2 para la url de origen.
Demostración de expresiones regulares en javascript: (Prueba para obtener ayuda)