2017-11-06 7 views
2

Ich habe eine Zeichenfolge wie http://google.com/search/q=<%= name %>.Java URI escaper, die wie die Javascript Unescape funktioniert

eine dritte Partei js Bibliothek, die ich keine Kontrolle darüber haben, entweicht diese zu "http://google.com/search/q=%3C%=%20name%20%%3E"

die Javascript erfolgreich unescape auf die ursprüngliche Zeichenfolge mit

unescape("http://google.com/search/q=%3C%=%20name%20%%3E") 

Aber Java URLDecode.decode("http://google.com/search/q=%3C%=%20name%20%%3E") ein IllegalArgumentException wegen der Würfe unescaped literal % Zeichen in der Zeichenfolge, die natürlich korrekt und nach Spezifikation ist, aber das macht serverseitige Verarbeitung kompliziert.

Bevor ich versuche, die fehlerhafte JS-Escape auf der Serverseite mit regulären Ausdrücken zu beheben (weil, wie erwähnt, kann ich die JS-Seite nicht ändern), würde ich gerne wissen, ob es eine permissivere Java-URL/URI gibt Dekodier-API, die genauso funktionieren würde wie Javascript's unescape, dh die eigenständigen "%" - Zeichen ignorieren und nur decodieren würde, was dekodierbar ist.

Antwort

1

Ich habe mich kurz in Apache-Bibliotheken umgesehen und bin auf das gleiche Problem gestoßen. Interessanterweise fand ich, als ich in der EMCAScript-Sprachspezifikation nachging, Pseudocode für die Funktion unescape(). Sie können dies unter https://tc39.github.io/ecma262/#sec-unescape-string

Es ist einfach genug, um eine einfache Implementierung dieser (siehe unten) und zumindest für das Beispiel in Ihrer Frage die Ausgabe übereinstimmt.

Jetzt ist dieser Code in keiner Weise optimiert und ich habe nicht ob darüber, ob Zeichencodierung relevant ist, aber es kann ein weniger schmerzhafter Weg nach vorne sein, als zu versuchen, Dinge mit Regex zu ringen.

public static String unescape(String s) { 
    StringBuilder r = new StringBuilder(); 
    for (int i = 0; i < s.length();) { 
     if (s.charAt(i) == '%') { 
      if (looksLikeUnicode(s, i)) { 
       r.append((char) fromHex(s, i + 2, i + 5)); 
       i += 6; 
       continue; 
      } 
      if (looksLikeAscii(s, i)) { 
       r.append((char) fromHex(s, i + 1, i + 2)); 
       i += 3; 
       continue; 
      } 
     } 
     r.append(s.charAt(i)); 
     i += 1; 
    } 
    return r.toString(); 
} 

private static boolean looksLikeUnicode(String s, int i) { 
    return (i + 5 < s.length()) && (s.charAt(i + 1) == 'u') && areHexDigits(s, i + 2, i + 5); 
} 

private static boolean looksLikeAscii(String s, int i) { 
    return (i + 2 < s.length()) && areHexDigits(s, i + 1, i + 2); 
} 

private static boolean areHexDigits(String s, int from, int to) { 
    for (int i = from; i <= to; ++i) { 
     if (isNotHexDigit(s.charAt(i))) { 
      return false; 
     } 
    } 
    return true; 
} 

private static boolean isHexDigit(char c) { 
    return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); 
} 

private static boolean isNotHexDigit(char c) { 
    return !isHexDigit(c); 
} 

private static int fromHex(String s, int from, int to) { 
    return Integer.parseInt(s.substring(from, to + 1), 16); 
} 
+1

Brilliant! Ich danke dir sehr! Nachdem Sie ECMAScript erwähnt haben, wurde mir klar, dass in der Tat Java's native ScriptingEngine verwendet werden kann, um das JS-Stil-Escaping auszuführen, zB 'new ScriptEngineManager(). GetEngineByName (" nashorn "). Eval (" unescape (% 3C% =% 20name % 20 %% 3E \ ")"), aber das bringt den unnötigen Aufwand für die Instanziierung der Skript-Engine mit sich, daher markiere ich dies als akzeptierte Antwort. – ccpizza

+0

Schön. Ich hätte an die Skript-Engine denken sollen. Es ist eine robustere Lösung, aber ja, ein bisschen schwerer. –

Verwandte Themen