在URL字符串中,如果百分号%后面跟了两个十六进制数字,那么它表示相应ASCII值所对应的字符,如%2F表示'/',%32表示'2'。%编码还可以进行嵌套,如%%32F可以解码成%2F,再进一步解码成/。如果没有任何百分号后面跟的是两个十六进制数字则无法再进行解码。
现在有一系列的URL,小强希望你帮忙进行百分号解码,直到无法再解码为止。
第一行一个正整数T(T<=10),表示T个测试样例;
对于每个测试样例,
输入字符串s,字符串不包含空白符且长度小于100,000。
有部分测试样例的字符串长度<=1,000。
输出T行,每行一个字符串,表示解码后的结果。
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; }
%
时弹出两个值来组合成新的字符,如果组合成的新字符是%
的话重复进行解码,否则送入栈中,继续遍历。 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()
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; } }
按照前面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; } }
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); } } }
思路:
使用一个栈,从后往前遍历字符串:
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(""); } } }
同样使用栈。
当加入字符时,判断栈顶三个字符是否能进行转码
%ab
形式 转码后,将转码的字符压栈。重复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)
''' 从后往前遍历,遇到数字,则直接入栈,遇到‘%’则出栈两个十六进制进制转换 若转换后的字符仍然是‘%’则递归调用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
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()))
#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; }