环境
java:1.8+
idea:2022.1.3
前言
今天发现了一个很奇怪的现象。
在内容相同的情况下:
- 单元测试,读取文件的文本,正则表达式可以匹配。
- 响应流中读取的却无法匹配
单元测试读取文本的方式,可以正常匹配
@Test
public void currentBase() {
ClassPathResource resource = new ClassPathResource("/html/a.html");
try {
InputStream inputStream = resource.getInputStream();
StringBuilder builder = TestUtil.getStringBuilderByInputStream(inputStream);
CurrentStarBO bo = OService.currentBase(builder.toString());
System.out.println(JSON.toJSONString(bo));
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static StringBuilder getStringBuilderByInputStream(InputStream inputStream) throws IOException {
byte[] inputByte = new byte[inputStream.available()];
StringBuilder builder = new StringBuilder();
//BufferedReader.readLine() 换行符不会被保留,导致格式不对,所以改用最原始的方式:InputStream.read()
while (inputStream.read(inputByte) != -1) {
String str = new String(inputByte, 0, inputByte.length, "gbk");
builder.append(str);
}
return builder;
}
响应流里读取的方式,却不可以匹配
public static String parseResponse2(HttpResponse<InputStream> response) {
if (response == null) {
return null;
}
int statusCode = response.statusCode();
if (statusCode != 200) {
return null;
}
try {
// 获取应答的所有头部属性
HttpHeaders resHeaders = response.headers();
//压缩方式
String contentEncoding = resHeaders.firstValue("Content-Encoding").orElse(null);
//内容类型
String contentType = resHeaders.firstValue("Content-Type").orElse(null);
if (contentType == null) {
return null;
}
String[] split = contentType.split(";");
String[] charsetArr = split[1].split("=");
InputStream is;
if (StringUtils.isNotBlank(contentEncoding) && contentEncoding.contains("gzip")) {
is = new GZIPInputStream(response.body());
} else {
is = response.body();
}
// 打印HTTP调用的应答内容长度、内容类型、压缩方式
System.out.printf("应答内容长度=%s, 内容类型=%s, 压缩方式=%s%n",
resHeaders.firstValue("Content-Length").orElse(null), contentType, contentEncoding);
//BufferedReader.readLine() 换行符不会被保留,导致格式不对,所以改用最原始的方式:InputStream.read()
StringBuilder builder = new StringBuilder();
byte[] inputByte = new byte[is.available()];
int i = 0, len;
while ((len = is.read(inputByte)) != -1) {
String str = new String(inputByte, 0, len, charsetArr[1]);
builder.append(str);
++i;
}
is.close();
System.out.println("读取了" + i + "次");
return builder.toString();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
这种方式获取的字符串,再去匹配正则表达式,就不行。
解决办法
昨晚弄到凌晨半,都没有弄出来,早上起来后,又来研究了下后,解决了。
如标题所说,我的正则表达式里是有\s
用来匹配换行符的。
原来的正则表达式:
<!-- 看到中间 \s?.+? -->
<div id=\"m\">(\d.*?)</div></td>\s?.*?<div id=\"c\">(\d.*?)</div></td>
我们可以看到\s?.+?
这句,本意是希望匹配换行符、空格符。
参考网上资料,改为:
修改后的正则表达式:
<div id=\"m\">(\d.*?)</div></td>[\s|\u3000|\u0020\u00A0]*.*?<div id=\"c\">(\d.*?)</div></td>
这样就可以了。
说明
以下内容来自网上资料:
为什么会出现这种情况,问题在于空格的种类:
- 半角空格
- \u0020
- 英文半角空格具有换行的效果,会出现不期望的换行现象;
- 可以通过正则表达式\s进行匹配
- 全角空格
- \u3000
- 不可通过正则表达式\s进行匹配
- 不间断空格
- \u00A0
- 主要用途用于禁止自动换行,在英文中主要用于避免类似**(100 KM)**这种文字被错误地分词排版成两行。
- 不可通过正则表达式\s进行匹配
可以看出,只有半角空格,才可以,其他类型的空格都不行。
所以:
我们就不要用\s匹配,直接用unicode编码匹配[\u3000|\u0020\u00A0]+
参考地址: