使用java中的URLDecoder将%解码到空间?

问题描述 投票:6回答:3

我有一个用例,我必须解码URI的queryParameter并执行操作(超出此问题的范围)。

假设我有一个URI,我必须解码它。现在我知道目前所有的%20都将被转换为空格,而创建URI空间应该用%20来表示,但可能会出现我可能获得带%作为空间的URI的情况。因此,我想将%转换为空格以保持向后兼容性。最后有一个注释有助于理解这个问题。

我用replaceall() %尝试了%20但是再次%20将成为%2020,还有许多其他例外。

这是读取UPI URI所必需的,根据NPCI的官方文件:

注意:考虑到当前的PSP应用程序被开发为“%”作为空格(“”),银行PSP应该同时支持“%”和“%20”,直到生态系统与修订版对齐为止。因此,应确保向后兼容性。

编辑1基于pshemo评论 -

我试过了

str.replaceAll("%(?![0-9a-fA-F])","%20")

一个不满足上述正则表达式的案例是“upi:// pay?pa = praksh%40kmbl&pn = Prakash%Abmar&cu = INR”

输出是pn - > Prakash“some othercharacter”mar

java utf-8 urlencode rfc upi
3个回答
1
投票

可能不是你想要的答案,但这可能会有所帮助:

public class Test {

    public static void main(String... a) {
        try {
            //
            String u = "upi://pay?pa=praksh%40kmbl&pn=Prakash%Abmar&cu=INR";
            System.out.println(decode(u));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String decode(String in) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < in.length(); i++) {
            char c = in.charAt(i);
            if (c == '%') {
                int decoded = Integer.parseInt(in.substring(i + 1, i + 3), 16);
                if (decoded >= 32 && decoded <= 126) { //Possible valid char
                    sb.append((char) decoded);
                    i += 2;
                } else { //not a valid char... maybe a space
                    sb.append(" ");
                }
            } else if (c == '+') {
                sb.append(" ");
            } else {
                sb.append(c);
            }
        }

        return sb.toString();
    }
}

有很多可能性,所以你可能需要一个“定制”的解决方案。上面的代码涵盖了一些情况。


1
投票

有趣的问题。你不能可靠地将%替换为空间,就像你已经看到的那样。您需要有关通过uri传输的内容的其他信息,然后缩小到必须更换的内容以及不需要更换的内容,例如,

%ZTest -> a space for sure
%Abababtest -> is it a space? probably... but we need to be sure that no strange characters or sequences are allowed
%23th%Affleck%20Street -> space? hex? what is what?

您需要更多信息才能可靠地解决该问题,例如:

  1. 哪些是允许的符号?或者哪些是允许解码的十六进制范围?
  2. 哪些查询参数是包含%作为空格的参数? (所以你可以只转换它们)
  3. 你需要解码西里尔文,阿拉伯文,汉字吗?
  4. 如果%20在URI中,我们可以假设没有%将是一个空间吗?或者它们是否可能在URI中显示为空格?

有了这些附加信息,解决问题应该更容易。

这是一个解决方案,但可能会让您朝着正确的方向前进(但请考虑底部的警告!):

Pattern HEX_PATTERN = Pattern.compile("(?i)%([A-F0-9]{2})?");
String CHARSET = "utf-8";
String ENCODED_SPACE = "%20";
String ALLOWED_SYMBOLS = "\\p{L}|\\s|@";

String semiDecode(String uri) throws UnsupportedEncodingException {
    Matcher m = HEX_PATTERN.matcher(uri);
    StringBuffer semiDecoded = new StringBuffer();
    while (m.find()) {
        String match = m.group();
        String hexString = m.group(1);
        String replacementString = match;
        if (hexString == null) {
            replacementString = ENCODED_SPACE;
        } else {
// alternatively to the following just check whether the hex value is in an allowed range... 
// you may want to lookup https://en.wikipedia.org/wiki/List_of_Unicode_characters for this
            String decodedSymbol = URLDecoder.decode(match, CHARSET);
            if (!decodedSymbol.matches(ALLOWED_SYMBOLS)) {
                replacementString = ENCODED_SPACE + hexString;
            }
        }
        m.appendReplacement(semiDecoded, replacementString);
    }
    m.appendTail(semiDecoded);
    return semiDecoded.toString();
}

样品用法:

String uri = "upi://pay?pa=praksh%40kmbl&pn=Prakash%Abmar&cu=INR";
String semiDecoded = semiDecode(uri);
System.out.println("Input: " + uri);
System.out.println("Semi-decoded: " + semiDecoded);
System.out.println("Completely decoded query: " + new URI(semiDecoded).getQuery());

将打印:

Input: upi://pay?pa=praksh%40kmbl&pn=Prakash%Abmar&cu=INR
Semi-decoded: upi://pay?pa=praksh%40kmbl&pn=Prakash%20Abmar&cu=INR
Completely decoded query: pa=praksh@kmbl&pn=Prakash Abmar&cu=INR

警告......要记住一些事项:

  • 此特定实现不适用于西里尔文,中文或其他字母,这些字母占用超过2个十六进制值(即单个字符的%##%##%##%##%##将不再被解码)
  • 你需要根据你的需要调整允许的符号(参见ALLOWED_SYMBOLS的正则表达式;现在它接受任何字母,任何空格和@
  • 假设是字符集utf-8

0
投票

我用于此的解决方案是不使用QR中提供的收款人姓名,并使用vpa查询PSP以获取正确的名称。这样你也可以确保收款人存在。

例如:

  1. 给定QR的URI为upi://pay?pa=someone@upi&pn=firstname%lastname&cu=INR
  2. 提取pa是someone@upi并用它从PSP获取用户名
  3. 除了名称和注释之外的任何内容都不能包含%%20,只需使用其他答案中提供的任何变通方法或使用更简单的注释解决方案,因为注释通常不太重要。
© www.soinside.com 2019 - 2024. All rights reserved.