在Java中将十六进制字符串转换为ASCII

Posted

技术标签:

【中文标题】在Java中将十六进制字符串转换为ASCII【英文标题】:Convert a String of Hex into ASCII in Java 【发布时间】:2011-06-14 17:07:23 【问题描述】:

我希望这不是一个愚蠢的问题,我查看了 5 个不同页面的 Google 结果,但没有找到任何相关内容。

我需要做的是将包含所有十六进制字符的字符串转换为 ASCII,例如

String fileName = 

75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000

我所看到的每一种方式都让人觉得你必须先将它放入一个数组中。有没有办法循环遍历每两个并转换它们?

【问题讨论】:

【参考方案1】:

查看Convert a string representation of a hex dump to a byte array using Java?

不管编码等你都可以new String (hexStringToByteArray("75546..."));

【讨论】:

【参考方案2】:

只需使用 for 循环遍历字符串中的每一对字符,将它们转换为一个字符,然后在字符串生成器的末尾敲击该字符:

String hex = "75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000";
StringBuilder output = new StringBuilder();
for (int i = 0; i < hex.length(); i+=2) 
    String str = hex.substring(i, i+2);
    output.append((char)Integer.parseInt(str, 16));

System.out.println(output);

或者(Java 8+),如果你觉得特别笨拙,可以使用臭名昭著的“固定宽度字符串拆分”技巧,让你可以用流做单线:

System.out.println(Arrays
        .stream(hex.split("(?<=\\G..)")) //https://***.com/questions/2297347/splitting-a-string-at-every-n-th-character
        .map(s -> Character.toString((char)Integer.parseInt(s, 16)))
        .collect(Collectors.joining()));

无论哪种方式,这都会给出以以下开头的几行:

uTorrent\Completed\nfsuc_ost_by_mustang\Pendulum-9,000 Miles.mp3

嗯... :-)

【讨论】:

本题获得“年度最自证其罪”奖。 哈哈好点,但幸运的是,这个文件来自一个曾经活过的案例,所以我很清楚,但我没想到哈哈!不过让我笑了:) 感谢帮助我加载的“berry120”! :) 鉴于字符串的大小是预先知道的,人们可能会优化StringBuilder 来保存它,甚至只使用char[]。当然,只有在经常运行时才有意义。 我知道这是一个老问题,但仅供参考 Guava 14 引入了一个 BaseEncoding 类,可以像 new String(BaseEncoding.base16().lowerCase().decode(hex), Charsets.US_ASCII) 一样使用 - BaseEncoding 实例可以缓存,因为它是不可变的【参考方案3】:

据我了解,您需要提取连续的十六进制数字对,然后解码该 2 位十六进制数字并获取相应的字符:

String s = "...";
StringBuilder sb = new StringBuilder(s.length() / 2);
for (int i = 0; i < s.length(); i+=2) 
    String hex = "" + s.charAt(i) + s.charAt(i+1);
    int ival = Integer.parseInt(hex, 16);
    sb.append((char) ival);

String string = sb.toString();

【讨论】:

【参考方案4】:
String hexToAscii(String s) 
  int n = s.length();
  StringBuilder sb = new StringBuilder(n / 2);
  for (int i = 0; i < n; i += 2) 
    char a = s.charAt(i);
    char b = s.charAt(i + 1);
    sb.append((char) ((hexToInt(a) << 4) | hexToInt(b)));
  
  return sb.toString();


private static int hexToInt(char ch) 
  if ('a' <= ch && ch <= 'f')  return ch - 'a' + 10; 
  if ('A' <= ch && ch <= 'F')  return ch - 'A' + 10; 
  if ('0' <= ch && ch <= '9')  return ch - '0'; 
  throw new IllegalArgumentException(String.valueOf(ch));

【讨论】:

【参考方案5】:
//%%%%%%%%%%%%%%%%%%%%%% HEX to ASCII %%%%%%%%%%%%%%%%%%%%%%
public String convertHexToString(String hex)

 String ascii="";
 String str;

 // Convert hex string to "even" length
 int rmd,length;
 length=hex.length();
 rmd =length % 2;
 if(rmd==1)
 hex = "0"+hex;

  // split into two characters
  for( int i=0; i<hex.length()-1; i+=2 )

      //split the hex into pairs
      String pair = hex.substring(i, (i + 2));
      //convert hex to decimal
      int dec = Integer.parseInt(pair, 16);
      str=CheckCode(dec);
      ascii=ascii+" "+str;
  
  return ascii;


public String CheckCode(int dec)
  String str;

          //convert the decimal to character
        str = Character.toString((char) dec);

      if(dec<32 || dec>126 && dec<161)
             str="n/a";  
  return str;

【讨论】:

【参考方案6】:

使用javax.xml.bind.DatatypeConverter 的最简单方法:

    String hex = "75546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c756d2d392c303030204d696c65732e6d7033006d7033006d7033004472756d202620426173730050656e64756c756d00496e2053696c69636f00496e2053696c69636f2a3b2a0050656e64756c756d0050656e64756c756d496e2053696c69636f303038004472756d2026204261737350656e64756c756d496e2053696c69636f30303800392c303030204d696c6573203c4d757374616e673e50656e64756c756d496e2053696c69636f3030380050656e64756c756d50656e64756c756d496e2053696c69636f303038004d50330000";
    byte[] s = DatatypeConverter.parseHexBinary(hex);
    System.out.println(new String(s));

【讨论】:

此解决方案给出的结果与接受的答案相同。 在我的例子中,字符串以 0x 开头,我得到一个异常,抱怨非法字符(在这种情况下是 x),所以我只需要做一个 substring(2) 来排除这些。 ^_^ 我有不同的输出,我不知道出了什么问题。字符串:B54075546f7272656e745c436f6d706c657465645c6e667375635f6f73745f62795f6d757374616e675c50656e64756c75与出DatatypeConverter:μ@ uTorrent的\完成\ nfsuc_ost_by_mustang \ Pendulu与DatatypeConverter:@uTorrent \完成\ nfsuc_ost_by_mustang \ Pendulu 跨度> 【参考方案7】:

对于这种情况,我将十六进制数据格式转换为 int 数组,我想将它们转换为 String。

int[] encodeHex = new int[]  0x48, 0x65, 0x6c, 0x6c, 0x6f ; // Hello encode
for (int i = 0; i < encodeHex.length; i++) 
   System.out.print((char) (encodeHex[i]));

【讨论】:

以上是关于在Java中将十六进制字符串转换为ASCII的主要内容,如果未能解决你的问题,请参考以下文章

在 C 中将 ascii char[] 转换为十六进制 char[]

如何在 Python 中将单个字符转换为其十六进制 ASCII 值?

如何在python中将单个字符转换为十六进制ascii值

在 C# 中将字符串转换为十六进制字符串

从以十六进制编码的 ASCII 字符串转换为纯 ASCII?

在 Java 中将字符串转换为十六进制