2017-11-29 1 views
2

2つの配列@Misterと@Mrsがあり、値に基づいて接頭辞を追加する必要があります。2つの配列に基づいてキャプチャされた単語に接頭辞を追加する必要があります

@Mister = qw(Parasuram Raghavan Srivatsan); 
@Mrs = qw(Kalai Padmini Maha); 

my $str = "I was invited the doctor Parasuram and Kalai and civil Engineer Raghavan and Padmini and finally Advocate Srivatsan and Maha"; 

#Mr. Parasuram Mr. Raghavan Mr. Srivatsan 
if(grep ($_ eq $str), @Mister) 
{ $str=~s/($_)/Mr. $1/g; } 

#Mrs. Kalai Mrs. Padmini Mrs. Maha` 
if(grep ($_ eq $str), @Mrs) 
{ $str=~s/($_)/Mrs. $1/g; } 

出力は次のようになります。

I was invited the doctor Mr. Parasuram and Mrs. Kalai and civil Engineer Mr. Raghavan and Mrs. Padmini and finally Advocate Mr. Srivatsan and Mrs. Maha

誰かがこのコードで間違った私がやっている方法といただきました!を簡素化でした。

答えて

6

シンプルなテイク

my $mr_re = join '|', @Mister; 
my $mrs_re = join '|', @Mrs; 

$str =~ s/\b($mr_re)\b/Mr. $1/g; 
$str =~ s/\b($mrs_re)\b/Ms. $1/g; 

(私が代わりにMrsの上記中立Msを使用することに注意してください。)

をしかし、我々は名前の途方に暮れる複雑さを考えると、\bが世話をしていません名前が別の名前を含むためのすべての可能な方法の簡単な例:-は容易に名前で発見されたと\b\wはない-を含んでいます\w\W、間のアンカーです。

したがって、Name-Anotherは、Nameだけでも同様に一致します。

内部にすることができ、英数字以外の文字(プラス_)がある場合は名前が負lookarounds?<!?!があなた以外の名前の文字に一致するアサーション($w_reに記載されていないもの)がある

my $w_re = /[a-z-]/i; # list all characters that can be in a name 

$str =~ s/(?<!$w_re)($mr_re)(?!$w_re)/Mr. $1/g; # same for Ms. 

を考えますそれらを消費しません。したがって、許容可能な名前を区切ります。

アクセントについても同様であり、おそらく様々な文化の名前に使用される他の文字についても同様です。満足のいく$w_reを形成するタスクは、難しいものになる可能性があります。

名前が複数の単語(スペース)で囲まれている場合は、名前を他の名前の中で処理するために、一般にそれらを解析する必要があります。それは複雑な作業です。ほとんどの正規表現がそれをカットしないモジュールを探します。

簡単な修正は、リストから別の名前を含む複数の単語を含む名前をチェックし、大文字と小文字を区別して処理することです。


ハードコードされた検証可能な名前の例では、上記の動作があります。文字列から正規表現を組み立てる際、あなたが実際に

my $mr_re = join '|', map { quotemeta } @Mister; 
my $mrs_re = join '|', map { quotemata } @Mrs; 

quotemetaを参照してください。特別な意味なしリテラル文字を意図しているように、しかし、一般的には、すべての(アスキー)非単語の文字がエスケープされていることを確認してください。正規表現の内部では\Qin perlbackslashおよびin perlreを参照してください。


この問題は、賢明な入力に大きく依存します。

名前がリストに複製されている場合、問題は悪いです:文中で繰り返す場合は、どちらがどちらであるかわからない場合は、それがMr.かMs.最初に重複をチェックする必要があります。

+0

恐ろしいチャンピオン... +1 – ssr1012

+0

@ ssr1012ありがとうございます - 大幅に更新されました – zdim

1

「誰かが私のやり方を単純化して、このコードで何が間違っているのだろうか」

最初の部分は、私もそれを行うような方法でzdimによって対処されていますが、(ちょうど、多分便利な誰かのためにつべこべ)「何を間違っている」の部分は私の意見では、対処するいくつかのより多く得ることができます:

if(grep ($_ eq $str), @Mister) { $str =~ s/($_)/Mr. $1/g; }

  • あなたのリストのエントリは、$ strを等しくすることはありません、私はあなたが条件と@listの両方の周りに括弧の追加のペアを使用やgrepのブロック形態(grep { $str =~ /$_/ } @Mister)を使用するか$str =~/$_/
  • を意味だと思います - さもなければgrep will引数としてリストを逃してしまいます。現時点で引数リストのリミッタとして既存のものが1つ必要です。
  • grepコマンドで使用されている$ _はコマンドの外部では使用できないため、$ str-substitutionは現在$ _の値が何であれ使用します。この例では、おそらくundefであるため、前の$ str 'の各文字の間に'が挿入されます。

私が言ったように、あなたの問題に対する完璧な解決策がzdimの回答に与えられていますが、「このコードの何が間違っているのか」と尋ねました。

1

@ ssr1012と他の読者:注意してください!この問題の普遍的な解決策があると思うのは魅力的です。しかし残念ながら@ zdimのアプローチでも、両方の配列に同じ名前が表示されると望ましくない結果が得られます。一方の配列の名前がもう一方の配列の名前と同じであれば、やはり難しいです開始または終了。ここ は、わずかに異なる名前を使用して、あなたの例です:

my @Mister = qw(Parasuram Mahan Srivatsan); 
my @Mrs = qw(Kalai Padmini Maha); 
... 

# I was invited the doctor Mr. Parasuram and Ms. Kalai and civil Engineer Mr. Ms. Mahan and Ms. Padmini and finally Advocate Mr. Srivatsan and Ms. Maha 

は「ミスターさんマハン」を参照してください?ユニバーサルソリューションには十分な情報がありません。衝突を避けるために、あなたの名前がハードコードされ、最初にチェックされていれば、これは信頼できるものです。

名前を追加しても、情報が不足している可能性があります。最初の名前の性別を推測することは、多くの言語文化では信頼できません。

+0

私はあなたの懸念を理解しています。どうもありがとうございます。 – ssr1012

+0

良い考えですが、(1)あなたの例の範囲内の他の人の名前は簡単に解決できます。私の答えの編集を参照してください。 (2)重複した名前は単に不都合な問題を示します。だから、リストは最初に重複のために比較されるべきです。しかし、完全な名前を持つことは、それらが重複していないので解決します。 Mr./Msです。推測する必要はありません。 (3)一方で、実際の問題は複数の単語を持つ名前を考えると始まります(私の答えにコメントされています) – zdim

+0

@zdim:私たちは意見の相違はしていませんが、経験は私に "名前は重複していないのでそれを解決する; - 私が扱っている言語(主に英語とスペイン語)では、性別に関しては完全な名前があいまいであり、データセットの名前が重複する可能性があります。あるシドニースミスはタイトルのために「Ms.」を使用し、シドニースミスは「Dr.」を使用し、第3のシドニースミスは「Mr.」を使用します。「問題は十分ではありません。 IRLは、各レコードが名前にのみ基づいていない一意の識別子を持つことを期待しています。 –

関連する問題