加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

java 中的 tab 字符转义问题

(2015-10-07 13:26:51)
标签:

365

it

分类: Java

今天有新同学在写 MR 的过程中,遇到一个问题:

在 hdfs 上有一份 log,里面的内容以 "\t" 字符串( 注意不是 tab )分割:


测试1\t测试2\t测试3\t测试4
该同学的 MR 代码大致如下:

System.out.println(line.split("\\t").length)
结果全是 1,意味着文本没有按预定模式分割成功。

后来该同学又直接复制文件内容与代码在 eclipse 中测试:


public class Test {

  public static void main(String[] args) {

    String line = "测试1\t测试2\t测试3\t测试4";
    String[] lineArr = line.split("\\t");
    System.out.println(lineArr.length + "\tArr[0]: " + lineArr[0]);

  }

}
发现 eclipse 中测试是“没问题”的,然后该同学就猜测 hadoop 环境有问题或者做了二次处理。

其实在之前这篇 《 Java split 导致字段丢失的一个“坑” 》  中我就提过,hadoop 压根就没重写过 jdk 的 String 基础类或者方法,所以明显不可能是 hadoop 的问题,应该是测试漏洞 + 理解错误。

现在我们还原下现场,测试尽量详细点:


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Test {

  public static void main(String[] args) throws IOException {

    FileReader reader = new FileReader("C:\\Users\\june\\Desktop\\a.txt");
    BufferedReader br = new BufferedReader(reader);
    String fileLine = null;
    while ((fileLine = br.readLine()) != null) {
      String[] lineArr = fileLine.split("\\t");
      System.out.println("从文件读,行内容:" + fileLine);
      System.out.println("Arr.length: " + lineArr.length + "\tArr[0]: " + lineArr[0]);
    }
    br.close();
    reader.close();
    
    System.out.println("------------------");

    String line = "测试1\t测试2\t测试3\t测试4";
    String[] lineArr = line.split("\\t");
    System.out.println("从字符串读,行内容:" + line);
    System.out.println("Arr.length: " + lineArr.length + "\tArr[0]: " + lineArr[0]);

  }

}
结果:

从文件读,行内容:测试1\t测试2\t测试3\t测试4
Arr.length: 1    Arr[0]: 测试1\t测试2\t测试3\t测试4
------------------
从字符串读,行内容:测试1   测试2     测试3     测试4
Arr.length: 4    Arr[0]: 测试1
可以看到如果我们直接给字符串赋值,如果带上 \t 的话,是会被转义的,不是字面意义上的 "\t",如果需要字面上的 \t 怎么办呢?

String line = "测试1\\t测试2\\t测试3\\t测试4";
String[] lineArr = line.split("\\\\t");
System.out.println("从字符串读,行内容:" + line);
System.out.println("Arr.length: " + lineArr.length + "\tArr[0]: " + lineArr[0]);

结果:

从字符串读,行内容:测试1\t测试2\t测试3\t测试4
Arr.length: 4      Arr[0]: 测试1
这里又有同学会问:为什么要 4 个 \\\\ 代表字面意义的 \t 呢?不是两个 \\ 就行了吗?

嗯,还是看代码:


String a1 = "[\t]";
String a2 = "[\\t]";
String a3 = "[\\\t]";
String a4 = "[\\\\t]";
String a5 = "[\\\\\t]";
String a6 = "[\\\\\\t]";
System.out.println(a1);
System.out.println(a2);
System.out.println(a3);
System.out.println(a4);
System.out.println(a5);
System.out.println(a6);

结果:
[    ]
[\t]
[\    ]
[\\t]
[\\    ]
[\\\t]
在 java 解析的时候只有 \t 和 \\t  会被转义识别为 tab,而 \\\\t 会被解析成 \\t,进而被识别为字面意义的 \t。

这个和 shell/awk/python 类似:


june@Win7 192.168.1.100  ~ >
echo "测试1\t测试2\t测试3\t测试4"|awk -F'\t' '{print NF"\t"$1}'
1       测试1\t测试2\t测试3\t测试4
june@Win7 192.168.1.100  ~ >
echo "测试1\t测试2\t测试3\t测试4"|awk -F'\\t' '{print NF"\t"$1}'
1       测试1\t测试2\t测试3\t测试4
june@Win7 192.168.1.100  ~ >
echo "测试1\t测试2\t测试3\t测试4"|awk -F'\\\\t' '{print NF"\t"$1}'
4       测试1
june@Win7 192.168.1.100  ~ >
关于字符串的转义与解析,java 算是简单的了,shell 下的水才深,经常让初学者找不着北。例如下面这个结果将会是什么?又如何获取想要的结果呢?

echo "测试1\t测试2\t测试3\t测试4"|awk -F"\\\\t" '{print NF"\t"$1}'

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有