文档章节

修改Pattern代码使Java正则表达式的group名称支持下划线 '_'

白爪
 白爪
发布于 2017/09/07 23:16
字数 824
阅读 18
收藏 0

为什么

由于工作是做数据ETL的,很多时候会使用到正则对数据进行提取,但是java的正则中的groupname不支持'_',官方的文档中是这样的:

Group name

A capturing group can also be assigned a "name", a named-capturing group, and then be back-referenced later by the "name". Group names are composed of the following characters. The first character must be a letter.

The uppercase letters 'A' through 'Z' ('\u0041' through '\u005a'), The lowercase letters 'a' through 'z' ('\u0061' through '\u007a'), The digits '0' through '9' ('\u0030' through '\u0039'), A named-capturing group is still numbered as described in Group number.

The captured input associated with a group is always the subsequence that the group most recently matched. If a group is evaluated a second time because of quantification then its previously-captured value, if any, will be retained if the second evaluation fails. Matching the string "aba" against the expression (a(b)?)+, for example, leaves group two set to "b". All captured input is discarded at the beginning of each match.

Groups beginning with (? are either pure, non-capturing groups that do not capture text and do not count towards the group total, or named-capturing group.

可以看到,只支持大写字母A-Z、小写字母a-z、数字0-9

查找源代码

在java.util.regex.Pattern类的以下源码中(jdk1.8.141是2789行)有下面这个方法:

    /**
     * Parses and returns the name of a "named capturing group", the trailing
     * ">" is consumed after parsing.
     */
    private String groupname(int ch) {
        StringBuilder sb = new StringBuilder();
        sb.append(Character.toChars(ch));
        while (ASCII.isLower(ch=read()) || ASCII.isUpper(ch) ||
               ASCII.isDigit(ch)) {
            sb.append(Character.toChars(ch));
        }
        if (sb.length() == 0)
            throw error("named capturing group has 0 length name");
        if (ch != '>')
            throw error("named capturing group is missing trailing '>'");
        return sb.toString();
    }

可以看到,源代码中对groupname的提取是一个while循环,当读取到的字符是小写字母(ASCII.isLower)、大写字母(ASCII.isUpper)、数字(ASCII.isDigit)的时候,会把这个字符添加到StringBuilder中,然后读取下个字符,知道不满足这个条件。

修改源代码

好,现在知道是这个原因了,怎么进行修改呢?
有很多人说不要修改大神写的代码,但是没办法。
由于不支持'_', 给工作带来挺多其它麻烦的,比如数据库中的字段名有'_',如果正则组不支持下划线的话,就需要一个正则组名和列名的映射关系,或者不用正则组名,使用正则组下标0,1,2...来映射。比较繁琐。 修改其实很简单,由于Pattern这个类在源代码中定义为final的,没法直接继承然后overwrite这个方法,就只能在自己的项目下新建一个regex包,将java.util.regex包的类都copy出来,总共是6个
输入图片说明

修改Pattern的上述方法,'_'这个字符在ASCII中是95,所以添加一个判断就可以了:

    private String groupname(int ch) {
        StringBuilder sb = new StringBuilder();
        sb.append(Character.toChars(ch));
        //TODO 增加了ch==95这个条件来支持正则组名支持下划线('_'),
        //源码为java.util.regex.Pattern的2793行
        while (ASCII.isLower(ch=read()) || ASCII.isUpper(ch) ||
               ASCII.isDigit(ch) || ch == 95) {
            sb.append(Character.toChars(ch));
        }
        if (sb.length() == 0)
            throw error("named capturing group has 0 length name");
        if (ch != '>')
            throw error("named capturing group is missing trailing '>'");
        return sb.toString();
    }

这样就可以使用我们自己Pattern类了,最后成功运行

public class MyTest {
    public static void main(String[] args) {
        Pattern pattern = Pattern.compile("\\s\\|\\s(?<my_name>worker_\\d+)\\s\\|");
        Matcher matcher = pattern.matcher("2017-02-14 23:58:04 | worker_10 | [ATMP05]");
        if (matcher.find()){
            //打印出来是"worker_10"
            System.out.println(matcher.group("my_name"));
        }
    }
}

最后,这个源码值改了一小部分,但是却让工作轻松了
当然,这样改是否会影响到其它东西需要时间的检验。

© 著作权归作者所有

共有 人打赏支持
白爪
粉丝 1
博文 2
码字总数 1888
作品 0
崇明
私信 提问
java.util.regex Pattern 正则

/**String 中 replaceAll(),matches(),split() 等方法,都是调用Pattern中的方法。学习了,瞬间觉得Pattern强大了 public String replaceAll(String regex, String replacement) {return Pat......

happycode
2014/04/02
0
1
正则表达式(四):Java regex

以下示例所使用 Java 版本为: 1.8.0 有了上一章 python 中的 re 模块的铺垫(正则表达式(三):python re模块),对于 Java 中正则的使用理解上会简单许多。 Java 作为一种被广泛使用的编程语...

zhipingChen
07/18
0
0
Java 正则表达式功能及应用

正则表达式,就是用某种模式去匹配一类字符串的一个公式,正则表达式由一些普通字符和一些元字符(metacharacters)组成。普通字符包括大小写的字母和数字,而元字符则具有特殊的含义,不管是...

浮躁的码农
2015/07/29
0
0
关于java中split的使用

之前在http://shukuiyan.iteye.com/blog/507915文中已经叙述过这个问题,但是最近一次笔试中居然有碰到了这个知识点,而且还做错了,囧!学艺不精啊。题目大概是这样的: Java代码 String s...

墨梅
2014/04/28
0
0
JAVA 正则表达式 (超详细)

(PS:这篇文章为转载,我不喜欢转载的但我觉得这篇文章实在是超赞了,就转了过来,这篇可以说是学习JAVA正则表达的必读篇。作者是个正真有功力的人,阅读愉快)   在Sun的Java JDK 1.40版本中...

毛朱
2012/10/25
0
1

没有更多内容

加载失败,请刷新页面

加载更多

大数据教程(6.1)hadoop生态圈介绍及就业前景

1. HADOOP背景介绍 1.1、什么是HADOOP 1.HADOOP是apache旗下的一套开源软件平台 2.HADOOP提供的功能:利用服务器集群,根据用户的自定义业务逻辑,对海量数据进行分布式处理 3.HADOOP的核心组...

em_aaron
13分钟前
0
0
hadoop垃圾回收站

在生产生,hdfs回收站必须是开启的,一般设置为7天。 fs.trash.interval 为垃圾回收站保留时间,如果为0则禁用回收站功能。 fs.trash.checkpoint.interval 回收站检查点时间,一般设置为小于...

hnairdb
昨天
1
0
腾讯与Github的魔幻会面背后的故事…

10月22日,腾讯开源管理办公室有幸邀请到Github新晋CEO Nat Friedman,前来鹅厂参观交流。目前腾讯已经有近70个项目在Github上开源,共获得17w stars,世界排名11位。Github是腾讯开源的主阵...

腾讯开源
昨天
1
0
单例模式

单例模式(Singleton pattern)属于创建型设计模式。 保证一个类仅有一个实例,并提供一个访问它的全局访问点。 通常我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对...

NinjaFrog
昨天
1
0
TypeScript基础入门之装饰器(三)

转载 TypeScript基础入门之装饰器(三) 继续上篇文章[TypeScript基础入门之装饰器(二)] 访问器装饰器 Accessor Decorator在访问器声明之前声明。 访问器装饰器应用于访问器的属性描述符,可用...

durban
昨天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部