首页 > 试题广场 >

百分号解码

[编程题]百分号解码
  • 热度指数:1397 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32M,其他语言64M
  • 算法知识视频讲解
在URL字符串中,如果百分号%后面跟了两个十六进制数字,那么它表示相应ASCII值所对应的字符,如%2F表示'/',%32表示'2'。%编码还可以进行嵌套,如%%32F可以解码成%2F,再进一步解码成/。如果没有任何百分号后面跟的是两个十六进制数字则无法再进行解码。

现在有一系列的URL,小强希望你帮忙进行百分号解码,直到无法再解码为止。

输入描述:
第一行一个正整数T(T<=10),表示T个测试样例;
对于每个测试样例,
输入字符串s,字符串不包含空白符且长度小于100,000。

有部分测试样例的字符串长度<=1,000。


输出描述:
输出T行,每行一个字符串,表示解码后的结果。
示例1

输入

1
%%32F

输出

/
#include<iostream>
#include<string>
using namespace std;
bool isHex(char a){
    if('A'<=a<='F'|| 'a'<=a<='f'|| '0'<=a<='9' )
        return true;
    else
        return false;
            
}
int hexCharToInt(char c) 
{  
        if (c >= '0' && c <= '9') return (c - '0'); 
        if (c >= 'A' && c <= 'F') return (c - 'A' + 10); 
        if (c >= 'a' && c <= 'f') return (c - 'a' + 10); 
        return 0; 
} 
bool char2Hex(char a){
    if('A'<=a<='F'|| 'a'<=a<='f'|| '0'<=a<='9' )
        return true;
    else
        return false;
            
}
 
int main(){
   int line=0;
   cin>>line;
   string str;
   int l=0;
   for(int i=0;i<line;i++){
       cin>>str;
       l=str.size();
        for(int j=l-3;j>=0;j--){
            while(str[j]=='%'){
                if( isHex(str[j+1]) && isHex(str[j+2])){
                    str[j]=char(hexCharToInt(str[j+1])*16+hexCharToInt(str[j+2]));
                    str.erase(j+1,2);
                    }
                else{
                    break;
                }
            }
        }
        cout<<str<<endl;
   }
    
   system("pause");
   return 0;
}

发表于 2020-06-11 23:46:07 回复(0)
  • 思路:倒着对字符串进行遍历,并使用栈来存储遍历的字符,当遇到%时弹出两个值来组合成新的字符,如果组合成的新字符是%的话重复进行解码,否则送入栈中,继续遍历。
def decode(stack):
    val1 = stack.pop()
    val2 = stack.pop()
    ch = chr(int(val1+val2,16))
    if ch == '%':
        stack = decode(stack)
    else:
        stack.append(ch)
    return stack

def main():
    N = int(input())
    for i in range(N):
        s = str(input())
        stack = []
        for c in s[::-1]:
            if c != '%':
                stack.append(c)
            else:
                stack = decode(stack)
        print("".join(stack[::-1]))
main()
发表于 2020-07-08 13:25:43 回复(1)
用Stack。从后往前遍历字符串,若不是%则push入栈,若是%则pop()两个字符,判断是数字则解码,解码后的字符push(),否则全push()入栈继续遍历
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int num = scanner.nextInt();
        for (int i = 0; i < num; i++) {
            sOut(scanner.next());
        }
    }

    private static Stack<Character> stack = new Stack<>();

    public static void sOut(String s) {

        int len = s.length();
        if (len < 3) {
            System.out.println(s);
            return;
        }
        stack.push(s.charAt(len - 1));
        stack.push(s.charAt(len - 2));
        for (int i = len - 3; i >=0 ; i--) {
            if (s.charAt(i) == '%') {
                deCode(stack.pop(), stack.pop());
                if (stack.peek() == '%') {

                }
            } else {
                stack.push(s.charAt(i));
            }
        }
        char[] chars = new char[stack.size()];
        int outSize = stack.size();
        for (int i = 0; i < outSize; i++) {
            chars[i] = stack.pop();
        }
        System.out.println(String.valueOf(chars));
    }

    private static void deCode(char a, char b) {
        if (!isHex(a) || !isHex(b)) {
            stack.push(b);
            stack.push(a);
            stack.push('%');
            return;
        }
        char c = (char)(hexChar2Int(a) * 16 + hexChar2Int(b));
        if (c == '%' && stack.size() >= 2) {
            deCode(stack.pop(), stack.pop());
            return;
        }

        stack.push((char)(hexChar2Int(a) * 16 + hexChar2Int(b)));
        return;
    }

    private static int hexChar2Int(char a) {
        if (a >= '0' && a <= '9') return a - '0';
        if (a >= 'a' && a <= 'f') return a - 'a' + 10;
        if (a >= 'A' && a <= 'F') return a - 'A' + 10;
        return 0;
    }

    private static boolean isHex(char a) {
        if (a >= '0' && a <= '9' || a >= 'a' && a <= 'f' || 'A' <= a  && a <= 'F') {
            return true;
        }
        return false;
    }

}


发表于 2020-06-22 09:11:09 回复(1)
#include <string>
#include <iostream>
#include <cctype>
using namespace std;

int main(void)
{

    int T = 0;
    while (cin >> T)
    {
        while (T--)
        {
            string str = "";
            string temp = "";
            cin >> str;
            int pos = str.rfind('%');//最后一个%的数组下标位置
            char c1=0,c2=0,replace=0;
            string hexstr="";
            while (pos != -1 && (pos + 2) < str.size())
            {
                 c1 = str[pos + 1];
                 c2 = str[pos + 2];
                if ((isdigit(c1) || isalpha(c1))
                    && (isdigit(c2) || isalpha(c2)))//判断这个个字符为十六进制字符
                {
                    hexstr=str.substr(pos + 1, 2);
                    replace = stoi(hexstr, 0, 16);
                    hexstr.clear();
                    //关键操作
                    str[pos]=replace;
                    str.erase(pos+1,2);
                }
                else
                {
                    temp = str.substr(pos) + temp;
                    str = str.substr(0, pos);
                }
                pos = str.rfind('%',pos);
            }
            temp = str + temp;
            cout << temp << endl;
        }
    }
    return 0;
}


发表于 2020-06-16 14:58:41 回复(3)

按照前面python的兄弟的思路,写了一个Java的,添加了注释

思路

从后往前遍历字符串,并使用栈来存储遍历的字符
当遇到的字符不是 '%' 时直接push;当遇到的字符是 '%' 时弹出两个值来进行解码,组成新的字符
如果组合成的新字符是 '%' 的话进行递归解码,如果不是则入栈
继续遍历,直到字符串开头

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Scanner;
import java.util.Stack;

public class Main {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        int groups = sc.nextInt();
        sc.nextLine();//吃掉回车符
        for (int i = 0; i < groups; i++) {
            System.out.println(decode(sc.nextLine()));
        }
    }

    public static String decode(String str){
        int len = str.length();
        // 边界情况
        if (len < 3)
            return str;

        Stack<Character> stack = new Stack<>();
        char[] array = str.toCharArray();
        //从后往前遍历字符串,进行解码
        for(int i = len - 1;i >= 0; i--){
            char c = array[i];
            if (c == '%'){
                // 当遇到的字符是 '%' 时弹出两个值来进行解码,组成新的字符
                char decodedChar = percentDecode(stack);
                stack.push(decodedChar);
            }else {
                // 遇到的字符不是 '%' 时直接push
                stack.push(c);
            }
        }

        //将栈的内容全部弹出来,返回结果
        char[] decodedArray = new char[stack.size()];
        for (int i = 0; i < decodedArray.length; i++) {
            decodedArray[i] = stack.pop();
        }
        return String.valueOf(decodedArray);
    }

    public static Character percentDecode(Stack<Character> stack){
        // 栈里没有内容可以弹了,直接返回百分号
        if (stack == null || stack.size() < 2){
            return '%';
        }

        String str = "";
        StringBuilder sb = new StringBuilder();
        sb.append('%');
        sb.append(stack.pop());
        sb.append(stack.pop());

        try {
            str = URLDecoder.decode(sb.toString(), "utf-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        char c1 = str.charAt(0);
        if (c1 == '%'){
            //递归解码
            c1 = percentDecode(stack);
        }
        return c1;
    }
}
编辑于 2020-09-24 16:55:06 回复(0)
跟用栈求解逆波兰表达式的操作类似,但由于此处的操作符"%"在操作数之前,因此从后往前遍历字符串中的字符:没有遇到"%"就压栈,遇到"%"就弹栈两个数进行解码,将解码后的数再次压栈。但这里需要注意一个问题,存在解码结果为"%"的情况,遇到这种情况就持续弹栈解码再压栈
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;
import java.util.Stack;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int T = Integer.parseInt(br.readLine());
        while(T-- > 0){
            char[] url = br.readLine().toCharArray();
            Stack<Character> stack = new Stack<>();
            for(int i = url.length - 1; i >= 0; i--){
                if(url[i] != '%'){
                    stack.push(url[i]);
                }else{
                    while(true){
                        char c1 = stack.pop();
                        char c2 = stack.pop();
                        char temp = (char)Integer.parseInt(c1 + "" + c2, 16);
                        if(temp != '%') {
                            // 只要解码后不是%就压栈,否则持续解码
                            stack.push(temp);
                            break;
                        }
                    }
                }
            }
            StringBuilder sb = new StringBuilder();
            while(!stack.isEmpty()) sb.append(stack.pop());
            System.out.println(sb);
        }
    }
}

发表于 2021-11-22 17:30:41 回复(1)
步骤简单,利用replace进行替换,但需要注重较多细节,完整通过
发表于 2020-08-12 11:28:42 回复(1)

思路:
使用一个栈,从后往前遍历字符串:

  • 如果不是"%"就压入栈
  • 如果是"%"就从栈顶取出两个字符组合成16进制并且转换为ASCII字符
    注意:
  • 16进制字符串转整型ASCII值可以直接使用Java包装类Integer提供的parseInte()方法
  • 整型ASCII值转字串常量可以直接强转
import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int t = sc.nextInt();
        String s = null;
        LinkedList stack;;
        for(int i = 0;i < t;i++) {
            stack = new LinkedList();
            s = sc.next();
            for(int j = s.length()-1;j >= 0;j--) {
                if(s.charAt(j) != '%') stack.addLast(s.charAt(j));
                else {
                    // 使用Integer提供的进制转换
                    String hex = new String(""+stack.removeLast()+stack.removeLast());
                    // 直接强转就可以得到对应的字符
                    char chr = (char)(Integer.parseInt(hex, 16));
                    // 如果转换结果得到“%”,就再进行一次
                    if(chr == '%') j++;
                    // 将得到的结果放入栈顶
                    else stack.addLast(chr);
                }
            }
            // 从后往前打印结果
            while(!stack.isEmpty()) System.out.print(stack.removeLast());
            System.out.println("");
        }
    }
}
发表于 2021-09-04 23:26:59 回复(0)

同样使用栈。

  1. 当加入字符时,判断栈顶三个字符是否能进行转码

    • 转码条件是:%ab形式
    • 原字符串后追加空字符:因为在新字符串准备压栈时才判断转码
  2. 转码后,将转码的字符压栈。重复1

    class Solution():
     def tochar(self,code):
         '''
         16进制数转字符
         '''
         code=''.join(code)
         return chr(int(code[1:],16))
    
     def f(self,s):
         s+=' '
         n=len(s)
         stack=[]
         for i in range(n):
    
             while len(stack)>=3 and stack[-1]!='%' and stack[-2]!='%' and stack[-3]=='%': # 加入char之后可能又组成新code了
                 code=stack[-3:] #取出后三个
                 stack.pop() # pop后3个
                 stack.pop()
                 stack.pop()
                 char=self.tochar(code)
                 stack.append(char)
             stack.append(s[i])
         return ''.join(stack).strip()
    n=int(input().strip())
    sol=Solution()
    for i in range(n):
     s=input().strip()
     res=sol.f(s)
     print(res)
发表于 2020-06-28 21:21:50 回复(0)
'''
从后往前遍历,遇到数字,则直接入栈,遇到‘%’则出栈两个十六进制进制转换
若转换后的字符仍然是‘%’则递归调用decode进行转换
'''
def sOUT(s):
    n = len(s)
    if n<3: return s
    stk = []
    for i in range(n-1,-1,-1):
        if s[i] == '%':
            decode(stk.pop(),stk.pop(),stk)
            # print('stk:',stk)
        else:
            stk.append(s[i])
    return ''.join(stk[::-1])
def decode(a,b,stk):
    num = chr(int(a+b,16))
    if num == '%' and len(stk)>=2:
        decode(stk.pop(),stk.pop(),stk)
        return
    stk.append(num)
    return
while True:
    try:
        n = int(input())
        for i in range(n):
            s = input()
            print(sOUT(s))
    except: break

发表于 2020-06-26 17:24:19 回复(0)
超时
def decodeUrl(url):
     
    index = len(url)
    while True:
        index = url[:index + 1].rfind('%')
        if index == -1:
            break
         
        b, e = index, index + 3
        hexstr = url[b: e]
        ch = chr(eval(hexstr.replace('%', '0x')))
        url = url[:b] + ch + url[e:]
         
    return url
 
if __name__ == "__main__":
     
    T = int(input())
    for t in range(T):
        print(decodeUrl(input()))


发表于 2020-06-14 11:26:05 回复(0)
#include<iostream>
#include<string.h>
#include<string>
#include<math.h>
#include<stack>
#include<algorithm>
using namespace std;
bool isok(char x, char y) {
	if (x >= 'a'&&x <= 'f')
		x = x - 32;
	if (y >= 'a'&&y <= 'f')
		y = y - 32;
	if (isdigit(x) || (x >= 'A'&&x <= 'F'))
	{
		if (isdigit(y) ||( y >= 'A'&&y <= 'F'))
			return true;
	}
	return false;
}


int main()
{
	int T;
	cin >> T;
	while (T--) {
		stack<int>p;
		string s;
		cin >> s;
		int len = s.length();
		int k = 0;
		for (int i = 0; i < len; i++) {
			if (s[i] == '%')
				p.push(i);
		}
		//从最后一个%开始往前处理,用空格替代已经编码过的字母。注意:
		//1、%后面两个字母的大小写问题
		//2、%编码出来的还是%
		while (!p.empty()) {
			int k = p.top();
			p.pop();

			int b = k + 1;
			while (s[b] == ' '&&b<len) {
				b++;
			}
			int c = b + 1;
			while (s[c] == ' '&&c < len) {
				c++;
			}
			if (b<len&&c<len&&isok(s[b], s[c]))
			{
				char x = s[b], y = s[c];
				if (x >= 'a'&&x <= 'f')
					x = x - 32;
				if (y >= 'a'&&y <= 'f')
					y = y - 32;

				int ans = 0;
				int n1, n2;
				if (y >= 'A'&&y <= 'F')
					n1 = y - 'A' + 10;
				else
					n1 = y - '0';
				if (x >= 'A'&&x <= 'F')
					n2 = x - 'A' + 10;
				else
					n2 = x - '0';
				ans = n2 * 16 + n1;
				char temp = (char)ans;
	
				if (temp == '%') {
					p.push(k);
				}
				s[k] = temp;
				s[b] = ' ';
				s[c] = ' ';
			}
		}
		//cout << s << endl;
		string temp;
		for (int i = 0; i < len; i++) {
			if(s[i]!=' ')
				temp = temp + s[i];
		}
		cout << temp << endl;
	}
	system("pause");
	return 0;
}

发表于 2020-06-12 10:16:08 回复(0)
loop = int(input())
for _ in range(loop):
    s = input()
    stack = []
    s = s[::-1]
    for i in s:
        stack.append(i)
        if i == '%':
            c = '%'
            while c == '%':
                stack.pop()
                a = stack.pop()
                b = stack.pop()
                c = chr(int("" + a + b, 16))
                stack.append(c)
    print("".join(stack[::-1]))
发表于 2020-05-25 22:23:50 回复(2)
import urllib.parse as p
n = int(input())
while n:
    n -= 1
    s = input()
    temp_len = len(s)
    temp = s
    while True:
        temp = p.unquote(temp)
        if len(temp) == temp_len:
            break
        else:
            temp_len = len(temp)
    print(temp)

使用 python3 内建库解决
发表于 2020-05-25 17:44:56 回复(0)