जावा जावास्क्रिप्ट के एनकोडरिकम्पोनेंट के बराबर है जो समान आउटपुट का उत्पादन करता है?


92

मैं जावा कोड के विभिन्न बिट्स के साथ प्रयोग कर रहा हूं, जो कि एक स्ट्रिंग के साथ आने की कोशिश कर रहा है जो उद्धरण, रिक्त स्थान और "विदेशी" यूनिकोड वर्णों को एन्कोड करेगा और जावास्क्रिप्ट के एन्कोडर्कोम्पोनेंट फ़ंक्शन के समान आउटपुट का उत्पादन करेगा ।

मेरा यातना परीक्षण स्ट्रिंग है: "ए" बी is "

अगर मैं फायरबग में निम्नलिखित जावास्क्रिप्ट स्टेटमेंट दर्ज करता हूं:

encodeURIComponent('"A" B ± "');

-तब मुझे मिलता है:

"%22A%22%20B%20%C2%B1%20%22"

यहाँ मेरा थोड़ा परीक्षण जावा कार्यक्रम है:

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class EncodingTest
{
  public static void main(String[] args) throws UnsupportedEncodingException
  {
    String s = "\"A\" B ± \"";
    System.out.println("URLEncoder.encode returns "
      + URLEncoder.encode(s, "UTF-8"));

    System.out.println("getBytes returns "
      + new String(s.getBytes("UTF-8"), "ISO-8859-1"));
  }
}

-यह कार्यक्रम आउटपुट:

URLEncoder.encode% 22A% 22 + B +% C2% B1 +% 22 देता है
getBytes रिटर्न "A" B ""

नजदीक पर बिना सिगार के! जावा का उपयोग करके UTF-8 स्ट्रिंग को एन्कोडिंग का सबसे अच्छा तरीका क्या है ताकि यह जावास्क्रिप्ट के समान आउटपुट का उत्पादन करे encodeURIComponent?

संपादित करें: मैं जल्द ही जावा 1.4 का उपयोग जावा 5 में कर रहा हूँ।

जवाबों:


63

कार्यान्वयन अंतरों को देखते हुए, मैं देखता हूं कि:

MDC परencodeURIComponent() :

  • शाब्दिक वर्ण (रेगेक्स प्रतिनिधित्व): [-a-zA-Z0-9._*~'()!]

जावा 1.5.0 प्रलेखन परURLEncoder :

  • शाब्दिक वर्ण (रेगेक्स प्रतिनिधित्व): [-a-zA-Z0-9._*]
  • अंतरिक्ष चरित्र " "को एक प्लस चिन्ह में परिवर्तित किया जाता है "+"

तो मूल रूप से, वांछित परिणाम प्राप्त करने के लिए, उपयोग करें URLEncoder.encode(s, "UTF-8")और फिर कुछ पोस्ट-प्रोसेसिंग करें:

  • की सभी घटनाओं की जगह "+"के साथ"%20"
  • उनके शाब्दिक प्रति-भागों में से "%xx"किसी का प्रतिनिधित्व करने की सभी घटनाओं को बदलें[~'()!]

मेरी इच्छा है कि आपने "% xx" की सभी घटनाओं को किसी भी ~ भाषा में [~ '() में से किसी एक का प्रतिनिधित्व करते हुए "शाब्दिक प्रति-भाग" पर वापस लिखा है। :( मेरा छोटा सिर इसे समझने में सक्षम नहीं है .......
शैलेंद्र सिंह राजावत

1
@Shailendra [~'()!]साधन "~"या "'"या "("या ")"या "!"। :) मैं regex मूल बातें सीखने की सलाह देता हूं, हालांकि, हालांकि। (मैंने इस पर भी विस्तार नहीं किया क्योंकि कम से कम दो अन्य उत्तर संबंधित जावा कोड दिखाते हैं।)
टॉमालक

3
के "+"साथ सभी घटनाओं को बदलना "%20"संभावित विनाशकारी है, जैसा "+"कि यूआरआई पथों में एक कानूनी चरित्र है (हालांकि क्वेरी स्ट्रिंग में नहीं)। उदाहरण के लिए, "a + b c" को एन्कोड किया जाना चाहिए "a+b%20c"; यह समाधान इसे परिवर्तित करेगा "a%20b%20c"। इसके बजाय, उपयोग करें new URI(null, null, value, null).getRawPath()
क्रिस निची

@ChrisNitchie यह सवाल का बिंदु नहीं था। सवाल था "जावा जावास्क्रिप्ट के एन्कोडरिकोमॉप्टेंट के बराबर है जो समान आउटपुट का उत्पादन करता है?" , "जेनेरिक जावा एनकोड-यूआरआई-घटक फ़ंक्शन?"
तोमलक

117

यह वह वर्ग है जिसके साथ मैं अंत में आया:

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;

/**
 * Utility class for JavaScript compatible UTF-8 encoding and decoding.
 * 
 * @see http://stackoverflow.com/questions/607176/java-equivalent-to-javascripts-encodeuricomponent-that-produces-identical-output
 * @author John Topley 
 */
public class EncodingUtil
{
  /**
   * Decodes the passed UTF-8 String using an algorithm that's compatible with
   * JavaScript's <code>decodeURIComponent</code> function. Returns
   * <code>null</code> if the String is <code>null</code>.
   *
   * @param s The UTF-8 encoded String to be decoded
   * @return the decoded String
   */
  public static String decodeURIComponent(String s)
  {
    if (s == null)
    {
      return null;
    }

    String result = null;

    try
    {
      result = URLDecoder.decode(s, "UTF-8");
    }

    // This exception should never occur.
    catch (UnsupportedEncodingException e)
    {
      result = s;  
    }

    return result;
  }

  /**
   * Encodes the passed String as UTF-8 using an algorithm that's compatible
   * with JavaScript's <code>encodeURIComponent</code> function. Returns
   * <code>null</code> if the String is <code>null</code>.
   * 
   * @param s The String to be encoded
   * @return the encoded String
   */
  public static String encodeURIComponent(String s)
  {
    String result = null;

    try
    {
      result = URLEncoder.encode(s, "UTF-8")
                         .replaceAll("\\+", "%20")
                         .replaceAll("\\%21", "!")
                         .replaceAll("\\%27", "'")
                         .replaceAll("\\%28", "(")
                         .replaceAll("\\%29", ")")
                         .replaceAll("\\%7E", "~");
    }

    // This exception should never occur.
    catch (UnsupportedEncodingException e)
    {
      result = s;
    }

    return result;
  }  

  /**
   * Private constructor to prevent this class from being instantiated.
   */
  private EncodingUtil()
  {
    super();
  }
}

5
एक टिप जोड़ना। एंड्रॉइड 4.4 में मैंने पाया कि हमें %0Aएंड्रॉइड इनपुट में एक वापसी कुंजी का मतलब बदलना होगा, या यह जेएस को क्रैश कर देगा।
Aloong

क्या आप यहां सब कुछ कवर करते हैं: developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
kamaci

1
@Aloong क्या आप जगह से मतलब है "%0A"? क्या चरित्र प्रतिस्थापन होगा? क्या यह सिर्फ खाली स्ट्रिंग है ""?
हेंड्रडब्ल्यूडब्ल्यू

15

जावा 6 के साथ शिप किए गए जावास्क्रिप्ट इंजन का उपयोग करना:


import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;

public class Wow
{
    public static void main(String[] args) throws Exception
    {
        ScriptEngineManager factory = new ScriptEngineManager();
        ScriptEngine engine = factory.getEngineByName("JavaScript");
        engine.eval("print(encodeURIComponent('\"A\" B ± \"'))");
    }
}

आउटपुट:% 22A% 22% 20B% 20% c2% b1% 20% 22

मामला अलग है लेकिन आप जो चाहते हैं उसके करीब है।


आह, क्षमा करें ... मुझे इस सवाल का उल्लेख करना चाहिए कि मैं जावा 1.4 पर हूं शीघ्र ही जावा 5 पर जा रहा हूं!
जॉन टॉपले

3
यदि जावास्क्रिप्ट ही एकमात्र उपाय है जिसे आप राइनो आज़मा सकते हैं, लेकिन यह इस छोटी सी समस्या के लिए बहुत अधिक है।
रवि वालेउ

3
यहां तक ​​कि अगर वह जावा 6 का उपयोग कर रहा था, तो मुझे लगता है कि यह समाधान शीर्ष पर है। मुझे नहीं लगता कि वह जावास्क्रिप्ट विधि को सीधे लागू करने का एक तरीका ढूंढ रहा है, बस इसे अनुकरण करने का एक तरीका है।
डाकू प्रोग्रामर

1
शायद। मुझे लगता है कि यदि आप कुछ भी नहीं कर सकते हैं जो आपके लिए ट्रिक करता है, तो सबसे आसान समाधान आपका खुद का एस्केप फंक्शन लिखना होगा। बस StringEscapeUtils वर्ग (जकार्ता कॉमन्स लैंग) से कुछ विधि को कॉपी करें और अपनी आवश्यकताओं के साथ इसे फिर से लागू करें।
रवि वालेउ

2
यह वास्तव में काम करता है, और यदि आप प्रदर्शन के बारे में चिंतित नहीं हैं ... मुझे लगता है कि यह अच्छा है।
2rs2ts

8

मैं उपयोग करता हूं java.net.URI#getRawPath(), जैसे

String s = "a+b c.html";
String fixed = new URI(null, null, s, null).getRawPath();

का मान fixedहोगाa+b%20c.html , जो आप चाहते हैं।

के उत्पादन के बाद के प्रसंस्करण के URLEncoder.encode()किसी भी प्लस कि कर रहे हैं मिटा जाएगा चाहिए यूआरआई में किया जाना है। उदाहरण के लिए

URLEncoder.encode("a+b c.html").replaceAll("\\+", "%20");

आपको देगा a%20b%20c.html, जिसकी व्याख्या की जाएगी a b c.html


यह सोचने के बाद कि यह सबसे अच्छा उत्तर होना चाहिए, मैंने इसे कुछ फ़ाइलनामों के साथ अभ्यास करने की कोशिश की, और यह कम से कम दो में, सिरिलिक पात्रों में से एक में विफल रहा। तो, नहीं, यह स्पष्ट रूप से पर्याप्त रूप से परीक्षण नहीं किया गया है।
AsGoodAsItGates

जैसे तार के लिए काम नहीं करता है:, http://a+b c.htmlयह एक त्रुटि फेंक देंगे
balazs

5

मैं एन्कोडर्कोम्पोनेंट के अपने संस्करण के साथ आया था, क्योंकि पोस्ट किए गए समाधान में एक समस्या है, अगर स्ट्रिंग में एक + मौजूद था, जिसे एन्कोड किया जाना चाहिए, तो यह एक स्थान पर परिवर्तित हो जाएगा।

तो यहाँ मेरी कक्षा है:

import java.io.UnsupportedEncodingException;
import java.util.BitSet;

public final class EscapeUtils
{
    /** used for the encodeURIComponent function */
    private static final BitSet dontNeedEncoding;

    static
    {
        dontNeedEncoding = new BitSet(256);

        // a-z
        for (int i = 97; i <= 122; ++i)
        {
            dontNeedEncoding.set(i);
        }
        // A-Z
        for (int i = 65; i <= 90; ++i)
        {
            dontNeedEncoding.set(i);
        }
        // 0-9
        for (int i = 48; i <= 57; ++i)
        {
            dontNeedEncoding.set(i);
        }

        // '()*
        for (int i = 39; i <= 42; ++i)
        {
            dontNeedEncoding.set(i);
        }
        dontNeedEncoding.set(33); // !
        dontNeedEncoding.set(45); // -
        dontNeedEncoding.set(46); // .
        dontNeedEncoding.set(95); // _
        dontNeedEncoding.set(126); // ~
    }

    /**
     * A Utility class should not be instantiated.
     */
    private EscapeUtils()
    {

    }

    /**
     * Escapes all characters except the following: alphabetic, decimal digits, - _ . ! ~ * ' ( )
     * 
     * @param input
     *            A component of a URI
     * @return the escaped URI component
     */
    public static String encodeURIComponent(String input)
    {
        if (input == null)
        {
            return input;
        }

        StringBuilder filtered = new StringBuilder(input.length());
        char c;
        for (int i = 0; i < input.length(); ++i)
        {
            c = input.charAt(i);
            if (dontNeedEncoding.get(c))
            {
                filtered.append(c);
            }
            else
            {
                final byte[] b = charToBytesUTF(c);

                for (int j = 0; j < b.length; ++j)
                {
                    filtered.append('%');
                    filtered.append("0123456789ABCDEF".charAt(b[j] >> 4 & 0xF));
                    filtered.append("0123456789ABCDEF".charAt(b[j] & 0xF));
                }
            }
        }
        return filtered.toString();
    }

    private static byte[] charToBytesUTF(char c)
    {
        try
        {
            return new String(new char[] { c }).getBytes("UTF-8");
        }
        catch (UnsupportedEncodingException e)
        {
            return new byte[] { (byte) c };
        }
    }
}

एक अच्छे समाधान के लिए धन्यवाद! दूसरों को पूरी तरह से ... अक्षम, IMO। शायद यह आज के हार्डवेयर पर बिटसेट के बिना भी बेहतर होगा। या 0 ... 127 के लिए दो हार्ड-कोडेड लॉन्ग।
जोनास एन

URLEncoder.encode("+", "UTF-8");पैदावार "%2B", जो उचित URL एन्कोडिंग है, इसलिए आपका समाधान है, मेरी माफी, पूरी तरह से अनावश्यक है। पृथ्वी पर URLEncoder.encodeस्थान क्यों नहीं बदलता है, %20यह मेरे से परे है।
2rs2ts


1

मैंने java.net.URI वर्ग का सफलतापूर्वक उपयोग किया है जैसे:

public static String uriEncode(String string) {
    String result = string;
    if (null != string) {
        try {
            String scheme = null;
            String ssp = string;
            int es = string.indexOf(':');
            if (es > 0) {
                scheme = string.substring(0, es);
                ssp = string.substring(es + 1);
            }
            result = (new URI(scheme, ssp, null)).toString();
        } catch (URISyntaxException usex) {
            // ignore and use string that has syntax error
        }
    }
    return result;
}

नहींं, यह पूरी तरह से सफल नहीं है, लेकिन यह अपेक्षाकृत ठीक है। हालांकि आपको अभी भी समस्याएं हैं। उदाहरण के लिए कार्डिनल चरित्र # जावा को 23% तक एन्कोड करेगा, जावास्क्रिप्ट उसे एनकोड नहीं करेगा। देखें: डेवलपर .mozilla.org/en-US/docs/Web/JavaScript/Reference/… जावास्क्रिप्ट जावास्क्रिप्ट नहीं करता है। एज एज़ 0-9; , /? : @ & = + $ - _। ! ~ * '() # और इन जावा में से कुछ के लिए जासूसी करेगा।
99Sono

निम्नलिखित अभिव्यक्ति के साथ एक UNIT परीक्षण करके अच्छी बात है: '' स्ट्रिंग अक्षरजैवस्क्रिप्टडॉटनॉटस्पेस = "ए-ज़-ज़ू0-9;; / ?: @ & = + $ -_।! ~ * () #"; '' '' कार्डिनल केवल एकमुश्त है। तो जावास्क्रिप्ट के साथ संगत बनाने के लिए ऊपर एल्गोरिथ्म को ठीक करना तुच्छ है।
९९ १। में ९९

1

इसका एक सीधा उदाहरण है रवि वलाऊ का हल:

public String buildSafeURL(String partialURL, String documentName)
        throws ScriptException {
    ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
    ScriptEngine scriptEngine = scriptEngineManager
            .getEngineByName("JavaScript");

    String urlSafeDocumentName = String.valueOf(scriptEngine
            .eval("encodeURIComponent('" + documentName + "')"));
    String safeURL = partialURL + urlSafeDocumentName;

    return safeURL;
}

public static void main(String[] args) {
    EncodeURIComponentDemo demo = new EncodeURIComponentDemo();
    String partialURL = "https://www.website.com/document/";
    String documentName = "Tom & Jerry Manuscript.pdf";

    try {
        System.out.println(demo.buildSafeURL(partialURL, documentName));
    } catch (ScriptException se) {
        se.printStackTrace();
    }
}

आउटपुट: https://www.website.com/document/Tom%20%26%20Jerry%20Manuscript.pdf

यह स्ट्रिंग के चर को कैसे पास करें, इस पर लोरेन शकीपोग्जा द्वारा टिप्पणियों में लटके सवाल का जवाब दिया गया है encodeURIComponent()। विधि scriptEngine.eval()एक लौटाती है Object, इसलिए इसे String.valueOf()अन्य विधियों के माध्यम से स्ट्रिंग में परिवर्तित किया जा सकता है ।


1

मेरे लिए यह काम किया:

import org.apache.http.client.utils.URIBuilder;

String encodedString = new URIBuilder()
  .setParameter("i", stringToEncode)
  .build()
  .getRawQuery() // output: i=encodedString
  .substring(2);

या एक अलग UriBuilder के साथ

import javax.ws.rs.core.UriBuilder;

String encodedString = UriBuilder.fromPath("")
  .queryParam("i", stringToEncode)
  .toString()   // output: ?i=encodedString
  .substring(3);

एक मानक पुस्तकालय का उपयोग करते हुए मेरी राय में मैन्युअल रूप से पोस्ट प्रोसेसिंग के बजाय एक बेहतर विचार है। इसके अलावा @ क्रिस जवाब अच्छा लग रहा था, लेकिन यह " http: // a + b c.html" जैसे यूआरएल के लिए काम नहीं करता है


1
मानक लाइब्रेरी का उपयोग करना अच्छा है ... ... जब तक आप मध्य वेयर नहीं होते हैं, और एक मानक लाइब्रेरी के एक अलग संस्करण पर निर्भर करते हैं, और फिर आपके कोड का उपयोग करने वाले किसी व्यक्ति को निर्भरता के साथ बेला करना पड़ता है, और फिर आशा है कि कुछ भी नहीं टूटेगा ...
अजाक्स

बहुत अच्छा होगा यदि यह समाधान काम करेगा, लेकिन यह अनुरोध के समान व्यवहार नहीं करता है encodeURIComponent। परिणाम के encodeURIComponentलिए रिटर्न , लेकिन आपका सुझाव रिटर्न । मुझे पता है कि इसका उल्लेख कई बार अन्य सवालों और जवाबों में किया गया है, लेकिन यहाँ पर इसका उल्लेख किया जाना चाहिए, इससे पहले कि लोग आँख बंद करके इस पर भरोसा करें। ?& %3F%26%20%3F%26+
फिलिप

1

यह मैं उपयोग कर रहा हूं:

private static final String HEX = "0123456789ABCDEF";

public static String encodeURIComponent(String str) {
    if (str == null) return null;

    byte[] bytes = str.getBytes(StandardCharsets.UTF_8);
    StringBuilder builder = new StringBuilder(bytes.length);

    for (byte c : bytes) {
        if (c >= 'a' ? c <= 'z' || c == '~' :
            c >= 'A' ? c <= 'Z' || c == '_' :
            c >= '0' ? c <= '9' :  c == '-' || c == '.')
            builder.append((char)c);
        else
            builder.append('%')
                   .append(HEX.charAt(c >> 4 & 0xf))
                   .append(HEX.charAt(c & 0xf));
    }

    return builder.toString();
}

यह जावास्क्रिप्ट के द्वारा हर चरित्र को प्रतिशत-एन्कोडिंग से आगे जाता है जो RFC 3986 के अनुसार एक अनारक्षित चरित्र नहीं है ।


यह ऑपोजिट रूपांतरण है:

public static String decodeURIComponent(String str) {
    if (str == null) return null;

    int length = str.length();
    byte[] bytes = new byte[length / 3];
    StringBuilder builder = new StringBuilder(length);

    for (int i = 0; i < length; ) {
        char c = str.charAt(i);
        if (c != '%') {
            builder.append(c);
            i += 1;
        } else {
            int j = 0;
            do {
                char h = str.charAt(i + 1);
                char l = str.charAt(i + 2);
                i += 3;

                h -= '0';
                if (h >= 10) {
                    h |= ' ';
                    h -= 'a' - '0';
                    if (h >= 6) throw new IllegalArgumentException();
                    h += 10;
                }

                l -= '0';
                if (l >= 10) {
                    l |= ' ';
                    l -= 'a' - '0';
                    if (l >= 6) throw new IllegalArgumentException();
                    l += 10;
                }

                bytes[j++] = (byte)(h << 4 | l);
                if (i >= length) break;
                c = str.charAt(i);
            } while (c == '%');
            builder.append(new String(bytes, 0, j, UTF_8));
        }
    }

    return builder.toString();
}


0

अमरूद लाइब्रेरी में PercentEscaper है:

Escaper percentEscaper = new PercentEscaper("-_.*", false);

"-_। *" सुरक्षित अक्षर हैं

'% 20' के साथ स्पेस से बचने के लिए PercentEscaper को झूठा कहता है, '+' नहीं


0

मैं String encodedUrl = new URI(null, url, null).toASCIIString(); उरोजों को कूटता था। urlI में मौजूदा लोगों के बाद पैरामीटर जोड़ने के लिएUriComponentsBuilder

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.