Java正则表达式正确,find()方法返回false,可能是因为\s无法匹配空格

本文探讨了在Java中,为何单元测试和响应流读取文件时正则表达式匹配出现差异,重点在于空格字符的影响。通过实例和解决方法,揭示了全角空格和不间断空格在正则表达式中的区别,以及如何使用Unicode编码解决匹配问题。
摘要由CSDN通过智能技术生成

环境

java:1.8+
idea:2022.1.3

前言

今天发现了一个很奇怪的现象。
在内容相同的情况下:

  1. 单元测试,读取文件的文本,正则表达式可以匹配。
  2. 响应流中读取的却无法匹配

单元测试读取文本的方式,可以正常匹配

@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]+

参考地址:

Java正则表达式正确,find()方法返回false,可能是因为\s无法匹配空格

python 爬虫爬取内容时, \xa0 、 \u3000 的含义

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

山鬼谣me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值