免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2741 | 回复: 8
打印 上一主题 下一主题

正则表达式的名字匹配问题 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2017-03-22 16:51 |只看该作者 |倒序浏览
各位大侠,我现在有一个问题亟待解决:
我有一个文件A,里面是一千多个名字,名字是不规则的,里面会有括号、下划线、空格等各种符号;
另外一个文件B,里面的名字更多,而且会有重复。
我现在需要将B中包含A的名字并且名字后面含有INN的全部提取出来。
例如,A里有一个叫做Captopril,那么B中有好多包含这个名字的,我只要取出下面B文件里面的2到4行(Captopril前面是起始^,后面有空格接一个小括号或中括号,里面一定有INN这个字符的)。

(-)-Captopril
Captopril (JP15/USP/INN)
Captopril (JP16/USP/INN)
Captopril [USAN:INN:BAN:JAN]
Captopril [USAN:USP:INN:BAN:JAN]
Captoprilum [INN-Latin]
L-Captopril
D-Captopril
Captopril-D7
Captopril-d3

我自己写了一个程序,但是因为B文件有将近10个G,跑起来特别得慢,不过我还是抛砖引玉放出来,希望有大神教教我怎么解决这个问题更有效率,非常感谢!
  1. use warnings;
  2. use diagnostics;
  3. use strict;
  4. my $input1="A.txt"; ###读进文件A
  5. my %hash;
  6. my $i;
  7. my @input1=split("\n",`cat $input1`);
  8. map{$hash{$_}=1}@input1;

  9. my $input="B.txt"; ###读进文件B
  10. open I, $input or die $!;
  11. open O, ">test.txt" or die $!;
  12. while(<I>){
  13.     chomp;
  14.     my $alias =$_;
  15.     foreach my $key (%hash){
  16.         if ($alias=~/^\Q$key\E\s\[.*INN.*\]$|^\Q$key\E\s\(.*INN.*\)$/i){ ### 对于文件B的每一行,都循环一次文件A的所有药名,匹配上则输出。
  17.         print O "$alias\n";
  18.         $i++;
  19.         }
  20.     }
  21. }
  22. print "$i\n";
  23. close I;
  24. close O;
复制代码


论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
2 [报告]
发表于 2017-03-22 17:17 |只看该作者
本帖最后由 sunzhiguolu 于 2017-03-22 17:22 编辑

1.> A 文件有多大?

代码中有个地方不是很明白:
  1. foreach my $key (%hash){
  2.    #...
  3. }
复制代码

能否解释下?

(-)-Captopril
Captopril (JP15/USP/INN)
Captopril (JP16/USP/INN)
Captopril [USAN:INN:BAN:JAN]
Captopril [USAN:USP:INN:BAN:JAN]
Captoprilum [INN-Latin]
L-Captopril
D-Captopril
Captopril-D7
Captopril-d3
以上这部分内容, 来自哪个文件? B 文件的文件结构怎样?
如果方便的话, 能否将 A, B 两个文件中具有代表性的数据示例贴出一小部分 并将所需结果贴出来, 方便观察些。

论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
3 [报告]
发表于 2017-03-22 18:19 |只看该作者
如果单纯从代码的角度看你写的代码,效能瓶颈来自哪里你应该最清楚了。

论坛徽章:
145
技术图书徽章
日期:2013-10-01 15:32:13戌狗
日期:2013-10-25 13:31:35金牛座
日期:2013-11-04 16:22:07子鼠
日期:2013-11-18 18:48:57白羊座
日期:2013-11-29 10:09:11狮子座
日期:2013-12-12 09:57:42白羊座
日期:2013-12-24 16:24:46辰龙
日期:2014-01-08 15:26:12技术图书徽章
日期:2014-01-17 13:24:40巳蛇
日期:2014-02-18 14:32:59未羊
日期:2014-02-20 14:12:13白羊座
日期:2014-02-26 12:06:59
4 [报告]
发表于 2017-03-22 20:56 |只看该作者
回复 1# wx2wx

$ ./get_INN.pl
Usage  : ./get_INN.pl KEY_FILE INN_FILE
Example: ./get_INN.pl A.txt    B.txt


$ ./get_INN.pl A.txt B.txt
Output file: test.txt
Total item: 4


$ cat get_INN.pl
#! /usr/bin/perl

use strict;
use warnings;

sub message{
  print <<EOF;
Usage  : $0 KEY_FILE INN_FILE
Example: $0 A.txt    B.txt
EOF
  exit 1;
}

message() if @ARGV != 2;

my $sFout = "test.txt";

my %hKey;
my $sCnt = 0;

my($sFkey, $sFinn)  = @ARGV;

open(my $FHkey, "<", $sFkey) or die "cannot open $sFkey file\n";
open(my $FHinn, "<", $sFinn) or die "cannot open $sFinn file\n";
open(my $FHout, ">", $sFout) or die "cannot oepn $sFout file\n";

print "Output file: $sFout\n";

while(<$FHkey>){
  s/^\s+|\s+$//g;
  next if(m/^(#|$)/);
  $hKey{$_} = 1;
}

while(<$FHinn>){
  my $sLine = $_;
  s/^\s+|\s+$//g;
  next if(m/^(#|$)/);
  next if(! m/\bINN\b/);
  my($sKey) = split;
  if(exists $hKey{$sKey}){
    ++$sCnt;
    print {$FHout} $sLine;
  }
}
print "Total item: $sCnt\n";

论坛徽章:
0
5 [报告]
发表于 2017-03-23 11:09 |只看该作者
回复 2# sunzhiguolu
A文件不是很大,将近1300个名字(1300行),我的程序就是把A文件里面的所有名字都存入了%hash的key,然后对Key做循环。我粘贴的那部分就是B文件的一部分内容。
A文件:
(-)-atenolol
(-)-catechin
(-)-isoprenaline
(-)-MK-801
(+)-chelidonine
(+)-isoprenaline
(+/-)-catechin
B文件:
(-)-Captopril
Captopril (JP15/USP/INN)
Captopril (JP16/USP/INN)
Captopril [USAN:INN:BAN:JAN]
Captopril [USAN:USP:INN:BAN:JAN]
Captoprilum [INN-Latin]
L-Captopril
D-Captopril
Captopril-D7
Captopril-d3
输出结果:
Captopril (JP15/USP/INN)
Captopril (JP16/USP/INN)
Captopril [USAN:INN:BAN:JAN]
Captopril [USAN:USP:INN:BAN:JAN]
等等。
谢谢



论坛徽章:
0
6 [报告]
发表于 2017-03-23 11:12 |只看该作者
回复 3# sunzhiguolu

对,主要就是每一行循环一千多次太慢了

论坛徽章:
0
7 [报告]
发表于 2017-03-23 11:13 |只看该作者
回复 4# jason680

谢谢您的代码,我来好好儿研究一下

论坛徽章:
307
程序设计版块每周发帖之星
日期:2016-04-08 00:41:33操作系统版块每日发帖之星
日期:2015-09-02 06:20:00每日论坛发贴之星
日期:2015-09-02 06:20:00程序设计版块每日发帖之星
日期:2015-09-04 06:20:00每日论坛发贴之星
日期:2015-09-04 06:20:00每周论坛发贴之星
日期:2015-09-06 22:22:00程序设计版块每日发帖之星
日期:2015-09-09 06:20:00程序设计版块每日发帖之星
日期:2015-09-19 06:20:00程序设计版块每日发帖之星
日期:2015-09-20 06:20:00每日论坛发贴之星
日期:2015-09-20 06:20:00程序设计版块每日发帖之星
日期:2015-09-22 06:20:00程序设计版块每日发帖之星
日期:2015-09-24 06:20:00
8 [报告]
发表于 2017-03-23 12:34 |只看该作者
回复 1# wx2wx
示例代码:
  1. #!/usr/bin/perl
  2. use strict;
  3. use warnings;

  4. my %hData = ();
  5. while (<DATA>){
  6.     last if (/\A\s*\z/);
  7.     s/\A\s+|\s+\z//g;
  8.     $hData{$_}++;
  9. }

  10. my $k = 'INN';
  11. while (<DATA>){
  12.     if (/\A(?<id>\w++)\s[\[(](?<keys>[^\])]+)/ and $hData{$+{id}}){
  13.         my %hKeys = map {$_, 1} split (/\W/, $+{keys});
  14.         print if ($hKeys{$k});
  15.     }
  16. }

  17. __DATA__
  18. (-)-atenolol
  19. (-)-catechin
  20. (-)-isoprenaline
  21. (-)-MK-801
  22. (+)-chelidonine
  23. (+)-isoprenaline
  24. (+/-)-catechin
  25. Captopril

  26. (-)-Captopril
  27. Captopril (JP15/USP/INN)
  28. Captopril (JP16/USP/INN)
  29. Captopril [USAN:INN:BAN:JAN]
  30. Captopril [USAN:USP:INN:BAN:JAN]
  31. Captoprilum [INN-Latin]
  32. L-Captopril
  33. D-Captopril
  34. Captopril-D7
  35. Captopril-d3

复制代码
perl abc.pl
------------------
Captopril (JP15/USP/INN)
Captopril (JP16/USP/INN)
Captopril [USAN:INN:BAN:JAN]
Captopril [USAN:USP:INN:BAN:JAN]


论坛徽章:
0
9 [报告]
发表于 2017-03-23 12:43 |只看该作者
谢谢4楼大神,我看了以后得出了一点经验,其实这种匹配没有什么特别好的办法,重要的就是在匹配之前要对被匹配的对象做一些简单的归一化处理,比如字母都变成大写,空格都变成下划线等等,另外就是在处理B文件的时候先判断一下是否包含INN,不包含就直接跳过,这样速度就会快很多。
谢谢各位。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP