JFlex中如何编写正确匹配邮箱的正则表达式
问题根因
你的代码匹配不到邮箱是三个明确的语法和逻辑错误导致的:
- 邮箱正则写法完全错误:
[^(.+)@(\S+)$]在JFlex里是取反字符集规则,含义是匹配单个不在(、.、+、@、\、S、)、$列表里的字符——因为你把整段正则放在了带开头^的方括号里,JFlex会把方括号内的所有内容拆成单个字符组成排除集,根本不会识别成你想要的“任意字符+@+非空字符”的邮箱匹配逻辑,甚至连@字符本身都属于这个规则的排除范围,不可能匹配到含@的邮箱。 - 语法不兼容:JFlex不支持通用正则里
\S(非空白字符)这类预定义简写,直接写会被识别成匹配反斜杠和S两个字符。 - 规则顺序错误:JFlex词法匹配遵循「最长匹配优先,同长度下先定义的规则优先」的逻辑,你把标识符规则
{L}({L}|{D})*放在了邮箱规则前面,邮箱开头的字母段会先被标识符规则匹配截断,根本轮不到邮箱规则生效。
修正方案
调整宏定义写法,把更长的邮箱匹配规则放到所有短规则的最前面,以下是可直接运行的修正代码:
// 宏定义部分 L = [a-zA-Z_] D = [0-9] // 匹配邮箱本地部分:允许字母、数字、下划线、点、短横,不能以点/短横开头 LocalPart = ({L}|{D})({L}|{D}|[._-])* // 匹配域名部分:允许字母数字短横,多段用点分隔,最后一段是2-6位的顶级域名 DomainPart = ({L}|{D}|[.-])*\.{L}{2,6} Email = {LocalPart}@{DomainPart} %{ public String lexeme; %} %% // 注意:Email规则必须放在最前面,避免被短的标识符、数字规则提前截断 {Email} {lexeme=yytext(); return Email;} {L}({L}|{D})* {lexeme=yytext(); return Identi;} ("-"{D}+")")|{D}+ {lexeme=yytext(); return Number;} . {return ERROR;}
如果需要支持更灵活的邮箱格式(比如加号别名、特殊字符),直接在
LocalPart的字符集里追加允许的字符即可,比如要支持test+tag@example.com这类带别名的邮箱,就把LocalPart修改为({L}|{D})({L}|{D}|[._+-])*。
编写注意事项
- 不要直接照搬其他编程语言的正则套用到JFlex中,JFlex的宏定义、字符类语法和通用正则有差异,不支持的简写字符类需要手动枚举允许的字符范围
- 定义宏时不要随意添加外层
[],只有表示单个可选字符集合的时候才需要用方括号包裹 - 所有匹配长度更长的token规则,必须放在短匹配规则的前面,避免被短规则提前截断匹配结果
内容的提问来源于stack exchange,提问作者coding2
相关产品推荐
相关产品推荐

