正则表达式不为空怎么写?常见写法与示例

资讯4天前发布 jdkjadmin
0 00
正则表达式不为空怎么写?常见写法与示例

正则表达式不为空怎么写?常见写法与示例

“匹配不为空”看起来简单,实际要先明确“不为空”指什么:只要字符串长度大于零,还是至少包含一个非空白字符?换行算不算字符?是否要求整个字符串都符合规则?这些问题不同,合适的正则表达式也不同。

最常见的写法是 .+,意思是“一个或多个点号能够匹配的字符”。不过,点号通常不匹配换行符,所以它并不总是等价于“任意非空字符串”。本文按使用场景介绍常见写法、边界和语言示例,并说明正则表达式能做什么、不能做什么。

先区分三种“不为空”

写正则之前,建议先选定目标:

  • 长度不为零:空字符串 "" 不通过;空格、制表符、换行等只要存在,也算非空。
  • 至少有一个非空白字符:空字符串和只含空白字符的字符串都不通过;" a " 通过。
  • 整个字符串符合指定字符规则:例如只能包含数字,且至少有一位。这既要求非空,也要求内容合法。

如果业务只是检查长度,优先考虑语言本身提供的长度判断。正则适用于字符规则需要和非空条件一起表达的情况,但不应为了使用正则而把简单判断写复杂。

常见写法速查

写法通常表示什么要留意的问题
.+一个或多个非换行字符点号默认通常不匹配换行;是否要求整个字符串取决于调用方式和锚点。
.*零个或多个非换行字符允许匹配空字符串,不能单独表示“至少一个”。
\S+一个或多个非空白字符空格、制表符等不能作为匹配内容;各引擎对空白字符的定义可能不同。
[\s\S]+一个或多个字符,包括换行常用于没有 DOTALL 模式或希望明确覆盖换行的场景。
(?=...)前瞻断言,不消耗字符适合将“至少存在一个字符”作为条件与其他规则组合;不是独立的字符匹配。

一、匹配至少一个字符:.+

量词 + 表示前面的模式重复一次或多次。因此,.+ 可以匹配至少一个点号所代表的字符。多数常见正则引擎中,点号默认不匹配行终止符,所以它适合“至少有一个非换行字符”的场景。

.+

例如,下列字符串在常见默认模式下通常会匹配:

  • a
  • hello
  • (一个空格也算一个字符)

而空字符串不匹配。需要注意的是,.+ 并不表示“至少有一个可见字符”,空格也能满足它。如果输入只有空格,模式仍然可以匹配。

是否匹配整个字符串

正则表达式可能用于搜索,也可能用于整体校验。很多 API 默认只要在字符串的某个位置找到匹配,就返回成功。若要表达“整个输入至少包含一个可匹配字符”,通常需要锚点,例如:

^.+$

这里的 ^ 和 $ 是常见的起始、结束锚点。但不同语言和引擎对锚点的细节并不完全相同:多行模式可能改变 ^、$ 的含义;在 JavaScript 等环境中,$ 还可能匹配字符串末尾换行符之前的位置。因此,若校验规则对“必须消费完整输入”有严格要求,应查阅目标引擎的说明,或使用该语言提供的整体匹配 API,而不要只凭锚点写法推断。

还有一个常见误区:.+ 中的点号在默认模式下通常不匹配换行。如果输入为多行文本,它可能只匹配某一行,或无法按预期匹配整个内容。

二、允许换行的非空字符串:[\s\S]+

如果“非空”表示只要包含任何字符就算通过,换行也要算字符,可以使用:

[\s\S]+

\s 通常代表空白字符,\S 通常代表非空白字符;字符类 [\s\S] 同时包含这两类,因此在常见引擎中可以匹配任意字符,包括换行。+ 则确保至少匹配一个字符。

这是一种常用的跨场景写法,但“任意字符”的精确范围仍由具体正则引擎和字符串编码模型决定。例如,某些引擎会以 UTF-16 码元而不是 Unicode 码点的方式处理字符;如果需要精确处理补充平面字符、字素簇或特定 Unicode 属性,应单独验证目标语言中的行为。

在支持 DOTALL 模式的引擎中,也可以让点号匹配换行,再写 .+。例如 JavaScript 使用 s 标志,Python 使用 re.DOTALL。这时要确认标志确实已启用,否则点号仍可能漏掉换行。显式写 [\s\S]+ 的好处是意图直观,不依赖 DOTALL 标志。

三、至少有一个非空白字符:\S+

如果空字符串和纯空白字符串都应被视为“空”,可以匹配一个或多个非空白字符:

\S+

例如,常见情况下,空格、制表符、换行构成的字符串不能匹配;" hello " 中的 hello 则可以匹配。

不过,\S+ 是“找到至少一个非空白片段”,不等于“校验整个字符串格式正确”。例如,在“必须是非空白内容,且不允许任何空格”的规则中,单独搜索 \S+ 会在 "hello world" 中找到 hello,于是搜索 API 可能报告匹配成功。要校验整个输入,需使用适合该语言的完整匹配方式,或添加正确的起止约束。

此外,\s、\S 对 Unicode 空白字符的定义会因语言、引擎、标志和版本而有差异。若规则涉及特定空白字符,例如不换行空格,建议查看所用引擎文档并用实际输入测试。不能仅凭“空白”二字假定所有语言的集合完全一致。

四、要求字符串非空,并且内容符合规则

实际验证通常不只是判断非空,还要限制字符。例如,只允许英文字母和数字,且至少有一个字符,可以写成:

^[A-Za-z0-9]+$

中间的字符类定义允许的内容,+ 确保至少一个字符。锚点用于表达整串校验;但不同 API、锚点语义和多行选项可能影响结果,严格校验时应优先使用语言提供的整体匹配方法。

如果允许字符中可能包含换行,或者规则是“任何字符至少一个,但还要满足其他条件”,可以用前瞻断言表达非空条件。例如,概念上可写为:

(?=[\s\S]+)

这个前瞻要求当前位置后至少存在一个可匹配字符,但它本身不消耗字符。通常会把它和其他模式组合,而不是单独用于提取内容。对于“仅判断长度是否大于零”这种需求,直接检查字符串长度更简单可靠。

JavaScript:判断长度与正则写法

下面的示例可以直接在浏览器控制台或 Node.js 中运行。它同时展示三种不同定义:

const values = ["", " ", "\n", "a", "a\n"];

for (const value of values) {
  const hasAnyCharacter = value.length > 0;
  const hasNonWhitespace = /\S/.test(value);
  const hasNonLineBreakCharacter = /.+/.test(value);

  console.log({
    value,
    hasAnyCharacter,
    hasNonWhitespace,
    hasNonLineBreakCharacter
  });
}

这里:

  • value.length > 0 判断 JavaScript 字符串是否包含至少一个 UTF-16 码元。对常规“字符串是否为空”的业务判断通常够用;它不是 Unicode 字素簇数量统计。
  • /\S/.test(value) 判断能否找到至少一个非空白字符。
  • /.+/.test(value) 会搜索至少一个非换行字符;它不是整体格式校验。

JavaScript 的 RegExp.prototype.test() 常用于查找是否存在匹配。对于非空判断,/[\s\S]+/.test(value) 可以把换行也纳入匹配:

const text = "\n";
console.log(/[\s\S]+/.test(text)); // true
console.log(/.+/.test(text));      // false

如果正则带有全局标志 g 或粘连标志 y,重复调用 test() 时会受 lastIndex 影响,可能出现同一个输入有时为真、有时为假的结果。用于单纯校验或判断时,通常不要给正则加 g 或 y。

Python:使用 re 模块

Python 的 re.search() 用于在字符串中搜索匹配;re.fullmatch() 则要求整个字符串都符合模式。以下代码可直接运行:

import re

values = ["", " ", "\n", "a", "a\n"]

for value in values:
    has_any_character = len(value) > 0
    has_non_whitespace = re.search(r"\S", value) is not None
    has_any_character_by_regex = re.fullmatch(r"[\s\S]+", value) is not None
    has_non_linebreak_character = re.search(r".+", value) is not None

    print(
        repr(value),
        has_any_character,
        has_non_whitespace,
        has_any_character_by_regex,
        has_non_linebreak_character,
    )

这里使用 re.fullmatch(r"[\s\S]+", value),要求整个字符串由一个或多个字符组成,因此空字符串不通过,包含换行的非空字符串可以通过。re.fullmatch() 从 Python 3.4 起提供;如果项目需要兼容更旧版本,应先确认运行时版本,或者使用相应的替代实现。

如果希望点号也匹配换行,Python 可使用 re.DOTALL:

import re

value = "first line\nsecond line"
matched = re.fullmatch(r".+", value, flags=re.DOTALL) is not None

print(matched)  # True

不启用 re.DOTALL 时,点号默认不匹配换行。不要把“点号代表任意字符”当成所有引擎、所有模式下都成立的规则。

Java:判断非空与正则匹配

Java 的 String.matches() 要求整个字符串匹配正则,不是“只要找到一段就算匹配”。以下代码可以直接运行:

public class NonEmptyRegex {
    public static void main(String[] args) {
        String[] values = {"", " ", "\n", "a", "a\n"};

        for (String value : values) {
            boolean hasAnyCharacter = !value.isEmpty();
            boolean hasNonWhitespace = value.matches("(?s).*\\S.*");
            boolean hasAnyCharacterByRegex = value.matches("(?s).+");

            System.out.println(
                "value=" + value
                + ", any=" + hasAnyCharacter
                + ", nonWhitespace=" + hasNonWhitespace
                + ", regexAny=" + hasAnyCharacterByRegex
            );
        }
    }
}

Java 字符串中的反斜杠需要在 Java 字符串字面量里再次转义,所以正则中的 \S 写成了 \\S。这里的 (?s) 是嵌入式 DOTALL 标志,让点号匹配行终止符。若只判断字符串是否为空,!value.isEmpty() 更直接;若还要求排除空白,可使用适合业务定义的空白判断方式,而不要默认 trim() 能覆盖所有 Unicode 空白情况。

常见错误与排查方法

错误一:把 .* 当成“至少一个字符”

* 表示零次或多次,因此 .* 能匹配空字符串。若要求至少一个点号可匹配的字符,应使用 .+;若要包括换行,可考虑 [\s\S]+ 或相应 DOTALL 模式。

错误二:把“长度非零”和“不是空白”混为一谈

" " 的长度大于零,但它没有非空白字符。长度判断、.+ 和 \S+ 对纯空格输入的结果并不一样。先确认业务定义,再选表达式。

错误三:忘记点号默认不匹配换行

多行文本、粘贴内容、带换行的配置值都可能触发这个问题。应通过测试用例明确验证换行行为,并选择 [\s\S]、DOTALL 标志或其他符合目标引擎的写法。

错误四:搜索匹配被误当成整串校验

很多 API 会在字符串中寻找任意一段匹配。像 \S+ 这样的模式可能在含空格的句子中找到一个单词,从而返回成功。如果规则要求整个输入符合条件,使用整体匹配 API,或根据引擎语义正确设置边界。

错误五:把“有一个字符”理解成“内容有效”

非空只是最低限度的存在性检查。.+ 不会检查邮箱、日期、标识符、数字范围或业务规则。即使正则匹配成功,也只能说明符合写出的模式,不能自动证明数据在业务上有效。

错误六:忽略语言字符串字面量的转义

在正则字面量语法中可以直接写 /\S+/;在 Java 字符串里通常要写 "\\S+";在 Python 中常用原始字符串 r"\S+"。正则本身的转义与编程语言字符串的转义是两层规则,抄写时要区分。

空字符串、缺失值与前后空格

表单字段“必填”还可能涉及没有提交字段、值为 null、值不是字符串等情况。这些不是正则表达式自身能统一处理的问题。应先在应用层检查输入是否存在、类型是否正确,再对字符串内容做验证。

另外,是否允许前后空格也应明确。若业务允许用户输入前后空格,但要求核心内容非空,可以先按业务规则去除首尾空白,再判断处理后的内容;若不允许擅自改写输入,则可以只验证是否含有非空白字符,并保留原值。不要在不清楚需求时自动调用裁剪操作,因为它会改变数据。

性能与安全边界

单独的 .+、\S+ 或 [\s\S]+ 结构简单,通常不属于容易引发灾难性回溯的典型模式。但安全性取决于完整表达式、引擎、输入长度和调用方式,不能据此推断任意正则都安全。复杂嵌套量词、存在大量重叠匹配可能性的分支,以及攻击者可控的超长输入,都可能造成性能问题。

正则表达式没有一个适用于所有语言和引擎的统一“最大长度”或“安全输入长度”。引擎实现、运行环境、应用配置和具体模式都会影响资源消耗。对于不可信输入,应根据业务为输入长度设置合理上限;若允许用户提交正则,还要考虑编译和匹配耗时,必要时选择支持资源限制的实现、设置超时或限制可用语法。不要把某个固定数字说成所有环境都安全的通用上限。

“非空校验”不是输入清洗,也不能防止 SQL 注入、跨站脚本、命令注入或路径穿越。安全处理应按数据最终进入的上下文采用参数化查询、上下文编码、允许列表和权限控制等措施。正则可以承担格式校验的一部分,但不能替代这些防护。

如何选择

  • 只判断字符串长度是否大于零:使用语言的长度或空字符串判断。
  • 至少需要一个非换行字符:可用 .+,并确认调用方式是否需要整串匹配。
  • 换行也算有效字符:可用 [\s\S]+,或在确认支持后启用 DOTALL 模式。
  • 至少需要一个非空白字符:搜索 \S 或按规则使用 \S+;若校验整个输入,必须使用整体匹配语义。
  • 还要限制允许的字符:把字符类或其他业务规则与“至少一次”的量词组合,并测试空串、空格、换行、合法值和非法值。

归根结底,+ 表示“至少一次”,是理解非空正则的关键;真正容易出错的地方,是点号是否匹配换行、空白如何定义,以及当前 API 究竟在搜索片段还是校验整串。把这三点说清楚,再用目标语言中的边界用例验证,通常就能写出符合预期的表达式。

© 版权声明

相关文章