找回密码
 注册
Simdroid-非首页
查看: 141|回复: 8

删除相邻的重复行(正则表达式应用)

[复制链接]
发表于 2013-7-7 20:03:25 | 显示全部楼层 |阅读模式 来自 英国
本帖最后由 lin2009 于 2013-7-7 21:52 编辑

删除相邻的重复行。

删除算例1,2中重复的第4、6、10行。第2行不删除,它与第1行部分重复,不算是重复行,为干扰项;第9行虽然与第5行相同但不相邻,应保留。
算例1,2是同一字符串在不同的环境下的例子,要求算例1,2用同一个正则表达式(除了算例2的读写文件操作外)。
这应该是正则表达式比较实用的功能,特别是算例2。

测试算例1:
str1 = ...   % 由论坛的实例改编。
        ['*SET_NODE_LIST *SET_NODE_LIST',char(13),...
        '*SET_NODE_LIST',char(13),...
        '%d',char(13),...
        '%d',char(13),...
        '*DEFINE_CURVE',char(13),...
        '*DEFINE_CURVE',char(13),...
        '%d,0,1.0,1.0,0.0,0.0',char(13),...
        '*LOAD_NODE_LIST',char(13),...
        '*DEFINE_CURVE',char(13),...
        '*DEFINE_CURVE',char(13),...
        '%d,%d,%d,1.0']
% 或者
str2 = sprintf('*SET_NODE_LIST *SET_NODE_LIST\n*SET_NODE_LIST\n%%d\n%%d\n*DEFINE_CURVE\n*DEFINE_CURVE\n%%d,0,1.0,1.0,0.0,0.0\n*LOAD_NODE_LIST\n*DEFINE_CURVE\n*DEFINE_CURVE\n%%d,%%d,%%d,1.0')

% str1和str2表面看上去一样,但实际上不相同。正则表达式应能兼容这两种情况。
isequal(size(str1),size(str2))   % 返回1
isequal(str1,str2)                   % 返回0

测试算例2:
对abc.m文件的内容(如下,即算例1的str内容,abc.m自行生成)进行操作,
可以用(fscanf,textread等)将整个文本内容读入str3,str3可能与str1,str2有区别。

*SET_NODE_LIST *SET_NODE_LIST
*SET_NODE_LIST
%d
%d
*DEFINE_CURVE
*DEFINE_CURVE
%d,0,1.0,1.0,0.0,0.0
*LOAD_NODE_LIST
*DEFINE_CURVE
*DEFINE_CURVE
%d,%d,%d,1.0


发表于 2013-7-7 21:26:52 | 显示全部楼层 来自 北京
Simdroid开发平台
本帖最后由 liuyalong008 于 2013-7-7 21:51 编辑

权当抛砖
针对算例1:
  1. s=regexprep(str,'(?<=^|\n)(.*?)\n(\1)\n','$1\n')
复制代码
  1. s =

  2. *SET_NODE_LIST *SET_NODE_LIST
  3. *SET_NODE_LIST
  4. %d
  5. *DEFINE_CURVE
  6. %d,0,1.0,1.0,0.0,0.0
  7. *LOAD_NODE_LIST
  8. *DEFINE_CURVE
  9. %d,%d,%d,1.0
复制代码
写成文本之后间隔都成了回车换行-->  \r\n
其他与算例1相同
  1. s=regexprep(fileread('C:\Users\Administrator\Desktop\abc.m'),...
  2.     '(?<=^|\r\n)(.*?)\r\n(\1)\r\n','$1\r\n')

  3. s =

  4. *SET_NODE_LIST *SET_NODE_LIST

  5. *SET_NODE_LIST

  6. %d

  7. *DEFINE_CURVE

  8. %d,0,1.0,1.0,0.0,0.0

  9. *LOAD_NODE_LIST

  10. *DEFINE_CURVE

  11. %d,%d,%d,1.0
复制代码
回复 不支持

使用道具 举报

发表于 2013-7-7 22:09:36 | 显示全部楼层 来自 北京
二楼 第一个只能针对\n而不能针对回车\r
懒得在编辑模式中改了
直接写3#了
  1. s=regexprep(str1,'(?<=^|(?=\s)[^   ])(.*?)(?=\s)[^   ](\1)(?=\s)[^   ]','$1\n')
复制代码

点评

正解!!! '(?<=^|[\n|\r])(.*)[\n|\r](\1)[\n|\r]' works!  发表于 2013-7-10 12:08
不能匹配的原因在于‘?’吧,你可以吧.*之后的?去掉试一试  发表于 2013-7-10 09:18
不能匹配的原因在于‘?’吧,你可以吧.*之后的?去掉试一试  发表于 2013-7-10 09:18
'(?<=^|(\n|\r))(.*?)(\n|\r)(\1)(\n|\r)' 也没有通过  发表于 2013-7-8 13:38
是不是用小括号(\n|\r)可以呢?  发表于 2013-7-8 13:31
回复 不支持

使用道具 举报

 楼主| 发表于 2013-7-8 16:34:05 | 显示全部楼层 来自 英国
str1 = ...
        ['*SET_NODE_LIST *SET_NODE_LIST',char(13),...
        '*SET_NODE_LIST',char(13),...
        '%d',char(13),...
        '%d',char(13),...
        '*DEFINE_CURVE',char(13),...
        '*DEFINE_CURVE',char(13),...
        '%d,0,1.0,1.0,0.0,0.0',char(13),...
        '*LOAD_NODE_LIST',char(13),...
        '*DEFINE_CURVE',char(13),...
        '*DEFINE_CURVE',char(13),...
        '%d,%d,%d,1.0',char(13)];

pat = '(?<=(^|\r+\n*|\r*\n+))(.*(\r+\n*|\r*\n+))\1+'; % 这个表达式对2个算例的三个情况都适用
% 不知道也不去探究matlab中回车与换行怎么表示、谁先谁后的问题,
% 但有一点是肯定的:除第一行外,其他各行行首行尾尾一定有回车或换行符或两者都有,
% 注意回车符、换行符至少有一个,不能都没有,因此用\r+\n*|\r*\n+匹配模式。
%(末行可能没有回车符、换行符,若此时刚好末行本身也是重复行,它就不会被删除!因此此正则表达式也不完善。)
% 加上第一行,则各行行首的匹配的字符为:(?<=(^|\r+\n*|\r*\n+))。行尾的表示道理相同。

mystr1 = regexprep(str1,pat,'$1')

% 或者可以用将符号^的意义改变一下,默认的情况下^表示字符串的首端,用(?m)使得^表示行首。
% (?m) Match the ^ and $ metacharacters at the beginning and end of a line.
% 但是不知道(?m)表示的line 与测试算例的str中的行概念是否一致。
% 应该不同的。
% 若相同的话,请看下例:pat2 = '(?m)^(.*?)$';   % 保险起见用非贪婪模式(.*?)。
mystr = regexprep(str,pat2,'1')
% 返回的结果应该是各行都被置换成了字符'1'。 但实际上是整个字符串被置换成'1'。与下面默认的情况相同。
pat2 = '(?-m)^(.*?)$';   % (?-m)为默认的方式。
mystr = regexprep(str,pat2,'1')

% 能否举出一个能反映 (?m)和(?-m)用法的典型例子,或者用(?-m)写出本例的正则表达式?


点评

第一个pat也可以写成 pat = '(?<=(^|[\r\n]+))(.*[\r\n]+)\1+';  发表于 2013-7-8 18:11
回复 不支持

使用道具 举报

发表于 2013-7-9 14:01:30 | 显示全部楼层 来自 北京
lin2009 发表于 2013-7-8 16:34
str1 = ...
        ['*SET_NODE_LIST *SET_NODE_LIST',char(13),...
        '*SET_NODE_LIST',char(13),...

第一个问题,关于回车加换行用
  1. pat = '(?<=(^|\r+\n*|\r*\n+))(.*(\r+\n*|\r*\n+))\1+'
复制代码
或者用:
  1. pat = '(?<=(^|[\r\n]+))(.*[\r\n]+)\1+'
复制代码
都可以解决,[\r\n]+是关键,str1和str2一个是回车一个是换行
按理说用[\r\n]应该可以来表示了,但是只有加上+才得到最终的正确
答案。+确实好用

第二个关于字符串首和行首的问题:
(?-m)是默认的方式,加不加无所谓。
(?m)表示是行首,其中行的判断以换行符\n来界定
  1. >> sr=regexprep(str2,'(?m)^(.*?)$','1')

  2. sr =

  3. 1
  4. 1
  5. 1
  6. 1
  7. 1
  8. 1
  9. 1
  10. 1
  11. 1
  12. 1
  13. 1
复制代码
'(?m)^(.*?)$'  中 (?m)^表示匹配行而非整个串,很明显str2中换行为\n

而(?-m)是默认的情况:
  1. >> sr=regexprep(str2,'(?-m)^(.*?)$','1')

  2. sr =

  3. 1

  4. >> sr=regexprep(str2,'^(.*?)$','1')

  5. sr =

  6. 1
复制代码
即用不用(?-m)没有影响

(?m)的典型算例,以1楼str2为例:
  1. sr=regexprep(str2,'(?m)^(.*?)^\1','$1')

  2. sr =

  3. *SET_NODE_LIST *SET_NODE_LIST
  4. *SET_NODE_LIST
  5. %d
  6. *DEFINE_CURVE
  7. %d,0,1.0,1.0,0.0,0.0
  8. *LOAD_NODE_LIST
  9. *DEFINE_CURVE
  10. %d,%d,%d,1.0
复制代码
其中的pattern为 '(?m)^(.*?)^\1'

用一个(?m)^表示这是行的开始后面跟tokens,然后需要注意的是
再加一个^来表示新的行首然后是重复tokens,$就没有必要加上了,
原因是:(.*?)中已经包括了\n了
回复 不支持

使用道具 举报

 楼主| 发表于 2013-7-9 16:57:30 | 显示全部楼层 来自 英国
liuyalong008 发表于 2013-7-9 14:01
第一个问题,关于回车加换行用或者用:都可以解决,[\r\n]+是关键,str1和str2一个是回车一个是换行
按理 ...

版主未看清第一个问题。(4#蓝色字体部分,(末行可能没有回车符、换行符,若此时刚好末行本身也是重复行,它就不会被删除!因此此正则表达式也不完善。))
将1#的str1,str2改编一下用来测试。
  1. str3 = ...   % 根据1#的str1改编,重复原末行一次,并去掉末行的回车或换行符。
  2.         ['*SET_NODE_LIST *SET_NODE_LIST',char(13),...
  3.         '*SET_NODE_LIST',char(13),...
  4.         '%d',char(13),...
  5.         '%d',char(13),...
  6.         '*DEFINE_CURVE',char(13),...
  7.         '*DEFINE_CURVE',char(13),...
  8.         '%d,0,1.0,1.0,0.0,0.0',char(13),...
  9.         '*LOAD_NODE_LIST',char(13),...
  10.         '*DEFINE_CURVE',char(13),...
  11.         '*DEFINE_CURVE',char(13),...
  12.         '%d,%d,%d,1.0',char(13),...
  13.         '%d,%d,%d,1.0'];

  14. % st4 % 根据1#的str2改编,重复原末行一次,末行无回车或换行符。
  15. str4 = sprintf('*SET_NODE_LIST *SET_NODE_LIST\n*SET_NODE_LIST\n%%d\n%%d\n*DEFINE_CURVE\n*DEFINE_CURVE\n%%d,0,1.0,1.0,0.0,0.0\n*LOAD_NODE_LIST\n*DEFINE_CURVE\n*DEFINE_CURVE\n%%d,%%d,%%d,1.0\n%%d,%%d,%%d,1.0')

  16. % 下面的2种模式均未通过测试,即均未删除末行重复行。(问题依然存在)
  17. pat = '(?<=(^|[\r\n]+))(.*[\r\n]+)\1+';
  18. mystr3 = regexprep(str3,pat,'$1')
  19. mystr4 = regexprep(str4,pat,'$1')

  20. pat = '(?<=(^|[\r\n]+))(.*[\r\n]+)\1+'
  21. mystr3 = regexprep(str3,pat,'$1')
  22. mystr4 = regexprep(str4,pat,'$1')
复制代码

点评

补充:楼上“(?m)的典型算例,以1楼str2为例”中的模式,也未能通过str3,str4的测试。  发表于 2013-7-9 17:20
回复 不支持

使用道具 举报

 楼主| 发表于 2013-7-9 17:17:49 | 显示全部楼层 来自 英国
liuyalong008 发表于 2013-7-9 14:01
第一个问题,关于回车加换行用或者用:都可以解决,[\r\n]+是关键,str1和str2一个是回车一个是换行
按理 ...

第二个关于字符串首和行首的问题:
(?-m)是默认的方式,加不加无所谓。
(?m)表示是行首,其中行的判断以换行符\n来界定
>> sr=regexprep(str2,'(?m)^(.*?)$','1')
可以通过str2,但是通不过str1的测试。1#str1的copy及测试代码如下
  1. str1 = ...   % 由论坛的实例改编。
  2. ['*SET_NODE_LIST *SET_NODE_LIST',char(13),...
  3. '*SET_NODE_LIST',char(13),...
  4. '%d',char(13),...
  5. '*DEFINE_CURVE',char(13),...
  6. '%d,0,1.0,1.0,0.0,0.0',char(13),...
  7. '*LOAD_NODE_LIST',char(13),...
  8. '*DEFINE_CURVE',char(13),...
  9. '%d,%d,%d,1.0']
  10. sr = regexprep(str1,'(?m)^(.*?),'1')
复制代码
回复 不支持

使用道具 举报

发表于 2013-7-9 18:48:38 | 显示全部楼层 来自 北京
lin2009 发表于 2013-7-9 16:57
版主未看清第一个问题。(4#蓝色字体部分,(末行可能没有回车符、换行符,若此时刚好末行本身也是重复行 ...

?m本来就是应用在行首的,所以只能通过str2(其中行以\n来标注)
对于存在\n的str2和从文本读取的同时存在\r\n的字符串可用:
  1. mystr4 = regexprep(str4,'(?m)^([^\n\r]*)[\r\n]+^\1','$1')
复制代码
  1. mystr4 = regexprep(str4,'(?m)^([^\n\r]*)[\r\n]+^\1','$1')

  2. mystr4 =

  3. *SET_NODE_LIST *SET_NODE_LIST
  4. *SET_NODE_LIST
  5. %d
  6. *DEFINE_CURVE
  7. %d,0,1.0,1.0,0.0,0.0
  8. *LOAD_NODE_LIST
  9. *DEFINE_CURVE
  10. %d,%d,%d,1.0
复制代码
  1. >> mystr5 = regexprep(str5,'(?m)^([^\n\r]*)[\r\n]+^\1','$1')

  2. mystr5 =

  3. *SET_NODE_LIST *SET_NODE_LIST

  4. *SET_NODE_LIST

  5. %d

  6. *DEFINE_CURVE

  7. %d,0,1.0,1.0,0.0,0.0

  8. *LOAD_NODE_LIST

  9. *DEFINE_CURVE

  10. %d,%d,%d,1.0
复制代码
str3 还没想好具体pattern,但是可以替换两次(也可针对str4)
  1. mystr3 = regexprep(regexprep(str3,'([\r\n])','\n'),'(?m)^([^\n\r]*)[\r\n]+^\1','$1')
复制代码
回复 不支持

使用道具 举报

发表于 2013-7-9 19:40:34 | 显示全部楼层 来自 英国
其实前天也考虑过这个问题了,结果忘记回帖:
  1. newstr = regexprep(str, '(?<=^|[\n\r])(.*)[\n\r](?=\1$|\1[\n\r])','')
复制代码

评分

1

查看全部评分

回复 不支持

使用道具 举报

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

本版积分规则

Simapps系列直播

Archiver|小黑屋|联系我们|仿真互动网 ( 京ICP备15048925号-7 )

GMT+8, 2024-9-22 15:12 , Processed in 0.046201 second(s), 18 queries , Gzip On, MemCache On.

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

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