找回密码
 立即注册
搜索
查看: 2262|回复: 15

[软件] 正则表达式的一个问题

[复制链接]
     
发表于 2020-10-30 12:51 来自手机 | 显示全部楼层 |阅读模式
不大好描述,就举个栗子吧。
比如待匹配的字符串是”后边都是我不需要的垃圾话喜欢你收到礼物时高兴的表情“
我预先不知道字符串的内容,但是知道里边可能包含这些东西(字典):喜欢你,收到礼物,你收到,礼物时高兴的表情
所以我写了一个循环拼接出表达式进行正则替换
(喜欢你|收到礼物|你收到|礼物时高兴的表情)+
但是显然,这个表达式只能匹配到垃圾话的前半部分。
并且显然,如果用字典里每个元素替换一次,也不能替换掉所有的垃圾话。
所以如果我想靠已知的字典,把垃圾话全部替换掉,是不是最好的办法是用字典里每个元素匹配一次,并记录匹配的start和end位置,然后如果start处于另一个匹配结果的start和end中间,就合并两个区域,最后把融合的区域的内容全部替换掉?
有更好的办法嘛:
回复

使用道具 举报

     
发表于 2020-10-30 13:29 来自手机 | 显示全部楼层
感觉没看懂楼主的需求,我猜测这样就OK了?Python3.7


—— 来自 Xiaomi MI 8, Android 10上的 S1Next-鹅版 v2.4.3
回复

使用道具 举报

     
 楼主| 发表于 2020-10-30 13:52 来自手机 | 显示全部楼层
糊状物 发表于 2020-10-30 13:29
感觉没看懂楼主的需求,我猜测这样就OK了?Python3.7


需要把原字符串使用字典替换为”后边都是我不需要的垃圾话”
你的运行结果是?我不了解Python,但是感觉你的代码不能实现这个
回复

使用道具 举报

     
发表于 2020-10-30 13:59 | 显示全部楼层
本帖最后由 dodolee 于 2020-10-30 14:06 编辑

你可能需要一个最优化算法,因为看起来你是想要使用字典中的词尽可能多的替换掉原始文本里面的文字,这个替换的过程不是独立的,先后顺序会影响结果(因为你的字典里面的单词存在重叠的部分)
文本量不大的话,试试简单的BFS可能就可以
回复

使用道具 举报

     
发表于 2020-10-30 14:04 | 显示全部楼层
先正则拿到任意匹配词,如果有匹配就拿到匹配词的index,最后截断是不是就行了?
回复

使用道具 举报

     
发表于 2020-10-30 14:06 | 显示全部楼层
你的需求就是避免字典中的关键字互相重叠导致匹配不全吧?
可以使用零宽正预测先行断言?=,这样匹配的是一个关键字之前的位置,本身宽度为零,不会互相重叠。
  1. >>> import re
  2. >>> matches = re.finditer(r'(?=(喜欢你|收到礼物|你收到|礼物时高兴的表情))', '后边都是我不需要的垃圾话喜欢你收到礼物时高兴的表情')
  3. >>> [(match.start(),match.group(1)) for match in matches]
  4. [(12, '喜欢你'), (14, '你收到'), (15, '收到礼物'), (17, '礼物时高兴的表情')]
复制代码

  1. (?=(喜欢你|收到礼物|你收到|礼物时高兴的表情))
复制代码
这个正则表达式本身匹配的是每个关键字前面的位置,然后内层的第一个捕获组匹配的是关键字本身。

回复

使用道具 举报

     
发表于 2020-10-30 14:08 | 显示全部楼层
不过这种匹配方式确实是不能直接替换的,要根据每个内层捕获组的起始位置和关键字的长度做合并,然后再替换。本质上和你说的一个个查找然后合并替换没有什么区别
回复

使用道具 举报

     
发表于 2020-10-30 14:22 来自手机 | 显示全部楼层
win8 发表于 2020-10-30 13:52
需要把原字符串使用字典替换为”后边都是我不需要的垃圾话”
你的运行结果是?我不了解Python,但是感觉 ...

我只是粗略敲出来,只要能正确匹配替换都是小事,换成re.sub函数完事了

—— 来自 Xiaomi MI 8, Android 10上的 S1Next-鹅版 v2.4.3
回复

使用道具 举报

     
 楼主| 发表于 2020-10-30 15:09 来自手机 | 显示全部楼层
dodolee 发表于 2020-10-30 13:59
你可能需要一个最优化算法,因为看起来你是想要使用字典中的词尽可能多的替换掉原始文本里面的文字,这个替 ...

简单了解了下,如果字典都是普通文本,的确是需要BFS。
实际情况是和栗子还有差别,字典本身包含有正则匹配,所以正则匹配的过程少不了了😂。
回复

使用道具 举报

     
 楼主| 发表于 2020-10-30 15:17 来自手机 | 显示全部楼层
小野賢章 发表于 2020-10-30 14:08
不过这种匹配方式确实是不能直接替换的,要根据每个内层捕获组的起始位置和关键字的长度做合并,然后再替换 ...

本来的想用字典生成正则后,缓存正则表达式从而减少后续的运算量。
不能一次完成匹配的话,就没有缓存的意义了,那就用兜底的方法,合并匹配的区域了
回复

使用道具 举报

     
发表于 2020-10-30 20:36 | 显示全部楼层
你先把正则表达式的集合扩张一下呗
回复

使用道具 举报

发表于 2020-10-30 22:04 | 显示全部楼层
这个举例太简单,你可能会需要语法判断,至少不能随意组合,你的关键字有重合,但重合以外不知道会不会有不存在关键字的内容,如果只是start end还好,各列举一遍,中间.*,但误伤可能挺大,或者你规定个列举的次数,所有中间.*,能降低些误伤
回复

使用道具 举报

     
发表于 2020-10-31 00:49 | 显示全部楼层
只有我一个人不知道楼主在说什么东西吗
回复

使用道具 举报

     
 楼主| 发表于 2020-10-31 17:21 | 显示全部楼层
我又陷入迷惑了,java的正则匹配在Matcher和replaceAll的支持程度是不同的嘛?同一个表达式,matcher命中了2次,正确地忽略掉了零宽断言,但是replaceAll把全部符号都替换掉了

  1.     public static void main(String[] r){
  2.         final String regex = "([…,,::?。!?!~<>《》【】()()]+)(?!\\p{P}*$)";
  3.         final String string = "测试1》》\n" +
  4.                 "测试2,测试3。\n" +
  5.                 "测试4:测试5》》\n" +
  6.                 "测试6";
  7.         final Pattern pattern = Pattern.compile(regex, Pattern.MULTILINE);
  8.         final Matcher matcher = pattern.matcher(string);
  9.         while (matcher.find()) {
  10.             System.out.println("match: " + matcher.group(1));
  11.         }
  12.         System.out.println("result:\n"+string.replaceAll(regex,"\n"));
  13.     }
复制代码


回复

使用道具 举报

发表于 2020-10-31 17:43 来自手机 | 显示全部楼层
@mistzzt 帮你叫一个计算机博士

—— 来自 Sony G8142, Android 9上的 S1Next-鹅版 v2.4.3
回复

使用道具 举报

     
发表于 2020-10-31 21:26 来自手机 | 显示全部楼层
win8 发表于 2020-10-31 17:21
我又陷入迷惑了,java的正则匹配在Matcher和replaceAll的支持程度是不同的嘛?同一个表达式,matcher命中了 ...

String.replaceAll没给你加mutiline啊

—— 来自 samsung SM-G9650, Android 10上的 S1Next-鹅版 v2.4.3
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|上海互联网违法和不良信息举报中心|网上有害信息举报专区|962110 反电信诈骗|举报电话 021-62035905|Stage1st ( 沪ICP备13020230号-1|沪公网安备 31010702007642号 )

GMT+8, 2024-9-25 03:28 , Processed in 0.088104 second(s), 5 queries , Gzip On, Redis On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表