浅析java和python的正则

在日常处理文本数据中,如果问我什么技术最重要和最常用,第一反应绝对不是虽说听起来low点但实际上效果并不差的字和词的one-hot编码,也不是什么据说可以解析词的相似度的word2vec(虽说效果也还可以),更别提近2,3年火得一塌糊涂的预训练语言模型(u1s1,身边认识搞nlp的,除了搞算法研究领域和知识图谱,不然没几个会在工程上用起这个)。而是出现了几十年了但目前在文本预处理领域占绝对地位,甚至可以说匹配领域都占有一席之地的陈旧技术——正则文法。

 

当然,从理论上说,其实正则文法也并不low,毕竟它可以算是乔姆斯基语言体系中有限状态自动机的应用——比它更高级的上下文无关文法其实到目前为止应用也不算特别多,更别提说可以完美表示自然语言的上下文有关文法(反正我没听过有实现过)。但主要是这东西出现太久了,我们都太习惯了它的存在,才感觉好像一般般。

 

先放最基本正则表达式的学习资料:——github上有一份37k star的链接,本渣称之为地表最强

https://github.com/ziishaned/learn-regex

 

但是,正则表示式也有一个尴尬的点,它单纯就是个表达式的匹配语法,不同的语言实现都不同,调用的api也不同,这也出现了我在浅析java和python的迭代里面说的问题——不同语言使用相同功能时候经常混淆,所以本文着重于看java和python的不同,具体正则的学习可以看上面大神写的github教程。

 

Java版的正则:

Java的正则主要运用了两个包,一个Pattern,一个Matcher。

可以理解为Pattern是用于正则表达式的编译表示,Matcher则是用于输入字符串进行解释和匹配操作的引擎。

Pattern其实就3个方法:split,matches,compile

其中核心就1个:compile。因为split算是特殊的,需要先complie再使用,而且Java字符串本身自带了带正则的split方法——日常直接用字符串的split不香么。而matches方法在Matcher类中也有另外的实现,因此没必要单独记。

Matcher则稍微复杂一点,它本身是Pattern进行compile后再调用matcher返回的结果,几乎所有的正则操作都在这个包上,但最常用也就下面几个方法:

matches:需要全文都匹配才返回true

lookingAt方法:从第一个字符开始部分匹配,但只返回第一个

find方法:部分匹配(这也是日常生活中最常用的),返回多个——常搭配循环while语句

 

当然,在数据处理的时候,更多是将匹配到的字符串进行分开或者替换,这时候就可以使用split或者replace函数,Java的String也自带了带有正则功能的函数(split,replaceAll,replaceFirst)。此外,还需要注意的一点是,在java中“\\”代表正则符号的一个“\", 因此,如果想匹配字符串含有“\”的模式,则需要是“\\\\”

public class regex_learn {

    public static void main(String[] args){
        // ####################### Pattern ###################################
        // matcher方法——整句全部匹配
        System.out.println(Pattern.matches(".*ef", "abcdefgef"));


        // split方法——两者等价Pattern.compile(delimeter).split(str)
        // split1和split2等价
        String[] split1 = Pattern.compile("123").split("123456123");
        String[] split2 = "123456123".split("123");

        // compile 方法
        Pattern p = Pattern.compile(".*ef");

        // ############################# Matcher方法 ###############################
        // matcher方法——整句全部匹配
        Pattern pattern = Pattern.compile(".*ef");
        Matcher matcher = pattern.matcher("abcdefgef");
        System.out.println(matcher.matches());

        // lookingAt()方法——从第一个字符开始部分匹配,有且只返回第一个
        Pattern pattern2 = Pattern.compile("ef");
        Matcher matcher2 = pattern2.matcher("abcdefgef");
        System.out.println(matcher2.lookingAt());

        // find用于循环——部分匹配,当存在多个的时候,返回多个
        Pattern pattern3 = Pattern.compile("ef");
        Matcher matcher3 = pattern3.matcher("abcdefgef");
        System.out.println("find方法");
        while (matcher3.find()){
            System.out.println(matcher3.group());
            // start和end需要已经匹配后再进行输出
            System.out.println(matcher3.start());
            System.out.println(matcher3.end());
        }

        // replace方法
        Pattern pattern4 = Pattern.compile("ef");
        Matcher matcher4 = pattern4.matcher("abcdefgef");
        System.out.println(matcher4.replaceFirst("efg"));// 只替换第一个
        System.out.println("abcdefgef".replaceFirst("ef","efg"));// 同上

        System.out.println(matcher4.replaceAll("efg"));// 替换全部
        System.out.println("abcdefgef".replaceAll("ef","efg"));// 同上

        // 非正则的replace
        System.out.println("abcdefgef".replace("ef","efg"));// 输入的第一个是字符串
    }

}

Python的正则

因为使用正则更多是在数据预处理阶段,因此一般来讲,python使用正则会比java更多。跟java的正则相比,python有如下特点:

1. str没有自带正则的函数

2. 没有pattern类(但有类似的实现),返回值几乎都是Matcher

3. api的名字不同

4. 所有方法都封装在re这个包里面

5. 在写正则的str时候,需要加上r""

其他不同详细可看代码注释

import re

# fullmatch 相当于java的match,返回Match对象
print(re.fullmatch(r"abc", "abc"))
print(re.fullmatch(r"abc", "abcd"))

# match()函数试图从字符串的开始部分对模式进行匹配,能匹配,则返回返回Match对象(只返回一个)
# 相当于java的lookingat
print(re.match(r"abc","abcdefabc"))
# <re.Match object; span=(0, 3), match='abc'>,能匹配,则返回返回Match对象
print(re.match(r"abc","babcdef"))
# None

# finditer,迭代器的每个是Match对象
# 相当于java的find
print(re.finditer(r"abc", "1abc3abc"))
for i in re.finditer(r"abc","1abc3abc"):
    print(i)

# findall 从任意位置匹配,返回全部列表
print(re.findall(r"abc", "1abc3abc"))

# search ,从任意位置匹配,只返回第一个匹配到的Match对象
# 这种搜索方法java貌似没有
print(re.search(r"abc","babcdefabc"))


# 相当于Pattern,预编译
compile_reg = re.compile(r"abc")
print(compile_reg.fullmatch("abc"))
print(compile_reg.fullmatch("abcd"))
print(compile_reg.match("abcdef"))
print(compile_reg.match("babcdef"))
print(compile_reg.search("babcdefabc"))
print(compile_reg.finditer("1abc3abc"))
print(compile_reg.findall("1abc3abc"))


test = 'abcdef'
if re.match(r'abc', test):
    print('ok')
else:
    print('failed')

# Match的对象的方法有
# python Matcher 的分组较为麻烦,要正则表达式本身存在()分组才可匹配
print(compile_reg.match("abcdef").groups()) #这里为空元组
print(compile_reg.match("abcdef").group())
print(compile_reg.match("abcdef").span())
print(compile_reg.match("abcdef").start())
print(compile_reg.match("abcdef").end())


# 替代,相当于java的replace
print(re.sub(r"abc", "0", "abcefgabc")) # 相当于java的replaceAll
print(re.sub(r"abc", "0", "abcefgabc",1)) # 相当于java的replaceFirst
print("abcefgabc".replace(r"abc", "0"))# python str不像java那样自带了正则

# 切分
print(re.split("a", "abcab"))
print("abcab".split("a"))# python str不像java那样自带了正则

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值