11

バックグラウンド

JasperServer でのドメイン作成の自動化を検討しています。ドメインは、アドホック レポートを作成するためのデータの「ビュー」です。列の名前は、人間が読める形式でユーザーに提示する必要があります。

問題

理論的には、組織がレポートに含めたい可能性のあるデータは 2,000 を超えます。データは、次のような人間にわかりやすい名前から提供されています。

支払い期間一致コード労働分配コーデッド従属関係アクションエンドオプションアクションエンドオプションデスアドレス型住所型記述履歴タイプ ps アドレス型ロール名銀行口座ステータス銀行口座ステータス記述銀行口座タイプ銀行口座タイプ記述受益者金額受益者クラス受益者パーセンテージ利益サブクラス受益者クラス受益者クラス記述利益アクションコード利益アクションコード化された利益年齢管理利益年齢管理説明年齢制限年齢管理通知期間

質問

そのような名前を次のように自動的に変更するにはどうすればよいでしょうか。

  • 支払期間マッチコード
  • 労働分配コードの説明
  • 扶養関係

アイデア

  • Google のDid you meanエンジンを使用しますが、TOS に違反していると思います。

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

言語

どの言語でも問題ありませんが、Perl などのテキスト パーサーが適していると思われます。(列名は英語のみです。)

不必要な予防

目標は、単語を分解する際の 100% の完璧さではありません。次の結果は許容されます。

  • registrationeffectivedate -> 登録発効日
  • registrationenddate -> 男性の登録日
  • registrationrequirementset -> 登録要件セット

いずれにせよ、人間は結果を再確認し、多くを修正する必要があります。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
dependentrelationship : 依存関係
actionendoption : アクション終了オプション
actionendoptiondesc : アクション終了オプション desc
addresstype : アドレスの種類
addresstypedesc : アドレスタイプの説明
historytype : 履歴タイプ
psaddresstype : * ps アドレス タイプ
rolename : ロール名
bankaccountstatus : 銀行口座のステータス
bankaccountstatusdesc : 銀行口座のステータスの説明
bankaccounttype : 銀行口座タイプ
bankaccounttypedesc : 銀行口座タイプ desc
受取人金額 : 受取人金額
beneficiaryclass : 受益者クラス
beneficiarypercent : 受益者の割合
benefitsubclass : 利益サブクラス
beneficiaryclass : 受益者クラス
beneficiaryclassdesc : 受益者クラス desc
benefitactioncode : 利益アクション コード
benefitactioncodedesc : 利益アクション コード desc
benefitagecontrol : ベネフィット エイジ コントロール
benefitagecontroldesc : ベネフィットの年齢管理の説明
ageconragelimit : * ageconrol の年齢制限
ageconrolnoticeperiod : * ageconrol 通知期間

A Spellchecker Used to Be Major feat of Software Engineeringも参照してください。

于 2010-10-04T16:02:36.363 に答える
1

私には2つのことが起こります:

  • これは、プログラムで自信を持って攻撃できるタスクではありません。なぜなら... 英単語はそのようには機能せず、他の単語で構成されていることが多いため、特定の文字列は「レポート」または「レポート年齢」ですか? 「時計」または「時計」?
  • 問題を攻撃する 1 つの方法は、anagアナグラムを検索する which を使用することです。結局のところ、「時計」は「時計」のアナグラムです...あとは、誤検知を取り除くだけです。
于 2010-10-05T12:17:54.903 に答える
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

以下は、辞書からの最長一致を試みる 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 に答える