11

背景

希望在 JasperServer 中自动创建域。域是用于创建临时报告的数据“视图”。列的名称必须以人类可读的方式呈现给用户。

问题

理论上,组织可能希望将超过 2,000 条可能的数据包含在报告中。数据来自非人类友好的名称,例如:

支付期匹配代码劳动分配编码esc 依赖关系操作endoption actionendoptiondesc addresstype addresstypedesc historytype psaddresstype rolename bankaccountstatus bankaccountstatusdesc bankaccounttype bankaccounttypedesc beficiaryamount beficiaryclass beeficiarypercent benefitsubclass beficiaryclass beficiaryclassdesc benefitactioncode benefitactioncodedesc benefitagecontrol benefitagecontroldesc ageconrolagelimit ageconrolnoticeperiod

问题

您将如何自动将此类名称更改为:

  • 支付期间匹配代码
  • 劳务分配代码描述
  • 依赖关系

想法

  • 使用谷歌的你的意思是引擎,但我认为它违反了他们的服务条款:

    lynx -dump «url» | grep "Did you mean" | awk ...

语言

任何语言都可以,但是像 Perl 这样的文本解析器可能更适合。(列名仅限英文。)

不必要的完美

我们的目标不是 100% 完美地分解单词;以下结果是可以接受的:

  • 注册生效日期 -> 注册生效日期
  • 登记结束日期 -> 登记男性倾向于日期
  • 注册要求集 -> 注册要求集

无论如何,人类都需要仔细检查结果并纠正许多。将一组 2,000 个结果减少到 600 个编辑将大大节省时间。专注于具有多种可能性的某些案例(例如,治疗师姓名)是完全忽略了这一点。

4

6 回答 6

14

有时,暴力破解是可以接受的:

#!/usr/bin/perl

use strict; use warnings;
use File::Slurp;

my $dict_file = '/usr/share/dict/words';

my @identifiers = qw(
    payperiodmatchcode labordistributioncodedesc dependentrelationship
    actionendoption actionendoptiondesc addresstype addresstypedesc
    historytype psaddresstype rolename bankaccountstatus
    bankaccountstatusdesc bankaccounttype bankaccounttypedesc
    beneficiaryamount beneficiaryclass beneficiarypercent benefitsubclass
    beneficiaryclass beneficiaryclassdesc benefitactioncode
    benefitactioncodedesc benefitagecontrol benefitagecontroldesc
    ageconrolagelimit ageconrolnoticeperiod
);

my @mydict = qw( desc );

my $pat = join('|',
    map quotemeta,
    sort { length $b <=> length $a || $a cmp $b }
    grep { 2 < length }
    (@mydict, map { chomp; $_ } read_file $dict_file)
);

my $re = qr/$pat/;

for my $identifier ( @identifiers ) {
    my @stack;
    print "$identifier : ";
    while ( $identifier =~ s/($re)\z// ) {
        unshift @stack, $1;
    }
    # mark suspicious cases
    unshift @stack, '*', $identifier if length $identifier;
    print "@stack\n";
}

输出:

payperiodmatchcode : 支付周期匹配代码
labourdistributioncodedesc : 劳动力分配代码 desc
依赖关系:依赖关系
actionendoption : 动作结束选项
actionendoptiondesc : 动作结束选项 desc
地址类型:地址类型
addresstypedesc : 地址类型描述
historytype : 历史类型
psaddresstype : * ps 地址类型
角色名:角色名
bankaccountstatus : 银行账户状态
bankaccountstatusdesc : 银行账户状态描述
bankaccounttype : 银行账户类型
bankaccounttypedesc : 银行账户类型描述
受益金额:受益金额
受益阶层:受益阶层
受益人百分比:受益人百分比
福利子类:福利子类
受益阶层:受益阶层
beneficiaryclassdesc : 受益人类别描述
福利操作代码:福利操作代码
benefitactioncodedesc : 福利操作代码 desc
福利控制:福利年龄控制
benefitagecontroldesc : 福利年龄控制 desc
ageconrolagelimit : * ageconrol 年龄限制
ageconrolnoticeperiod : * ageconrol 通知期

另请参阅A Spellchecker Used to Be a Major Feat of Software Engineering

于 2010-10-04T16:02:36.363 回答
1

我将您的列表减少到我关心的 32 个原子术语,并将它们放在正则表达式中的最长优先排列中:

use strict;
use warnings;

my $qr 
    = qr/ \G # right after last match
          ( distribution 
          | relationship 
          | beneficiary 
          | dependent 
          | subclass 
          | account
          | benefit 
          | address 
          | control 
          | history
          | percent 
          | action 
          | amount
          | conrol 
          | option 
          | period 
          | status 
          | class 
          | labor 
          | limit 
          | match 
          | notice
          | bank
          | code 
          | desc 
          | name 
          | role 
          | type 
          | age 
          | end 
          | pay
          | ps 
          )
    /x;

while ( <DATA> ) { 
    chomp;
    print;
    print ' -> ', join( ' ', m/$qr/g ), "\n";
}

__DATA__
payperiodmatchcode
labordistributioncodedesc
dependentrelationship
actionendoption
actionendoptiondesc
addresstype
addresstypedesc
historytype
psaddresstype
rolename
bankaccountstatus
bankaccountstatusdesc
bankaccounttype
bankaccounttypedesc
beneficiaryamount
beneficiaryclass
beneficiarypercent
benefitsubclass
beneficiaryclass
beneficiaryclassdesc
benefitactioncode
benefitactioncodedesc
benefitagecontrol
benefitagecontroldesc
ageconrolagelimit
ageconrolnoticeperiod
于 2010-10-04T17:06:51.620 回答
1

我想到两件事:

  • 这不是您可以自信地以编程方式攻击的任务,因为...英语单词不是这样工作的,它们通常由其他单词组成,那么,给定的字符串是“reportage”还是“report age”?“时计”还是“时计”?
  • 解决问题的一种方法是使用anagwhich finds anagrams。毕竟,“timepiece”是“timepiece”的变位词……现在你只需要清除误报。
于 2010-10-05T12:17:54.903 回答
1

这是一个从字典中尝试最长匹配的 Lua 程序:

local W={}
for w in io.lines("/usr/share/dict/words") do
    W[w]=true
end

function split(s)
    for n=#s,3,-1 do
        local w=s:sub(1,n)
        if W[w] then return w,split(s:sub(n+1)) end
    end
end

for s in io.lines() do
    print(s,"-->",split(s))
end
于 2010-10-07T20:01:59.653 回答
0

鉴于某些单词可能是其他单词的子字符串,尤其是多个单词被拼凑在一起的情况下,我认为像正则表达式这样的简单解决方案已经过时了。我会使用一个完整的解析器,我在 ANTLR 方面的经验。如果你想坚持使用 perl,我很幸运使用通过 Inline::Java 生成为 Java 的 ANTLR 解析器。

于 2010-10-04T15:32:45.167 回答
0

Peter Norvig 有一个很棒的 python 脚本,它具有使用 unigram/bigram 统计的分词功能。你想看看 ngrams.py 中函数 segment2 的逻辑。详细信息在《美丽数据》(Segaran 和 Hammerbacher,2009 年)一书中的自然语言语料库数据一章中。http://norvig.com/ngrams/

于 2013-09-03T20:54:24.493 回答