programing

자바스크립트 인코딩과 동등한 자바동일한 출력을 생성하는 URIC 컴포넌트?

nicescript 2023. 1. 3. 21:51
반응형

자바스크립트 인코딩과 동등한 자바동일한 출력을 생성하는 URIC 컴포넌트?

나는 따옴표, 공백, "exotic" 유니코드 문자를 포함한 문자열을 인코딩하고 자바스크립트의 인코딩과 동일한 출력을 생성하는 것을 고안하기 위해 자바 코드의 다양한 비트를 실험해 왔다.URIC 컴포넌트 기능

내 고문 테스트 문자열은 "A" B ± "입니다.

Firebug에 다음 JavaScript 문을 입력하면

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 ± "를 반환합니다.

아슬아슬하지만 여송연은 안 돼!Java를 사용하여 UTF-8 문자열을 인코딩하여 JavaScript의 문자열과 동일한 출력을 생성하는 가장 좋은 방법은 무엇입니까?encodeURIComponent?

편집: Java 1.4를 곧 Java 5로 이행할 예정입니다.

제가 생각해낸 수업은 다음과 같습니다.

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();
  }
}

실장상의 차이를 보면, 다음과 같은 것을 알 수 있습니다.

위의 MDC:

  • 리터럴 문자(regex 표현): [-a-zA-Z0-9._*~'()!]

의 Java 1.5.0 매뉴얼:

  • 리터럴 문자(regex 표현): [-a-zA-Z0-9._*]
  • 공백 문자" "플러스 기호로 변환됩니다."+".

따라서 기본적으로 원하는 결과를 얻으려면URLEncoder.encode(s, "UTF-8")그런 다음 몇 가지 후처리를 수행합니다.

  • 모든 발생을 치환하다"+"와 함께"%20"
  • 모든 발생을 치환하다"%xx"의 어느쪽인가를 대표하는 모양[~'()!]문자 그대로의 상대역으로 돌아가서

Java 6에 동봉된 Javascript 엔진을 사용하는 경우:


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

케이스는 다르지만 당신이 원하는 것에 더 가깝습니다.

사용하고 있다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()URI에 있을 법한 모든 장점을 지웁니다.예를들면

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

너에게 줄 것이다a%20b%20c.html이는 다음과 같이 해석됩니다.a b c.html.

난 내 버전의 인코딩을 생각해냈어URIComponent는 게시된 솔루션에 문제가1개 있기 때문에 String에 부호화해야 할 +가 있으면 공백으로 변환됩니다.

제 수업은 다음과 같습니다.

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 };
        }
    }
}

http://blog.sangupta.com/2010/05/encodeuricomponent-and.html에서 문서화된 또 다른 구현 방법을 생각해냈습니다.실장에서는 Unicode 바이트도 처리할 수 있습니다.

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;
}

다음은 Ravi Wallau의 솔루션 예시입니다.

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

, String 를 「String」에 건네주는 방법에 관한 합니다.encodeURIComponent() ★★scriptEngine.eval()Object 、 [ String ]를 통해 할 수 .String.valueOf()른른른른

나에게 이것은 효과가 있었다:

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

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

또는 다른 URI Builder를 사용하여

import javax.ws.rs.core.UriBuilder;

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

내 생각에는 수동으로 사후 처리하는 것보다 표준 라이브러리를 사용하는 것이 더 좋은 생각입니다.또, @Chris의 답변은 좋아 보였지만, 「http://a+b c.html」등의 URL에서는 동작하지 않습니다.

사용하고 있는 것은 다음과 같습니다.

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에 따르면 예약되지 않은 문자가 아닌 모든 문자를 백분율로 인코딩하여 Javascript를 능가합니다.


다음은 oposite 변환입니다.

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();
}

하였습니다.String encodedUrl = new URI(null, url, null).toASCIIString();url을 합니다.의 뒤에 하는 경우url 용 i i i i를 쓴다.UriComponentsBuilder

인코딩 구현에 사용할 수 있는 google-http-java-client 라이브러리에서 PercentEscaper 클래스를 찾았습니다.URIC 구성 요소는 꽤 쉽게.

google-http-java-client javadoc의 PercentEscaper google-back-client 홈

Guava 라이브러리에는 PercentEscaper가 있습니다.

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

".*"는 안전한 문자입니다.

false says PercentEscaper가 '+'가 아닌 '%20'으로 공간을 이스케이프합니다.

언급URL : https://stackoverflow.com/questions/607176/java-equivalent-to-javascripts-encodeuricomponent-that-produces-identical-outpu

반응형