3

ウィキペディアでは、人々が使用できる多くの顔文字を定義しています。このリストを文字列内の単語に一致させたい。私は今これを持っています:

$string = "Lorem ipsum :-) dolor :-| samet";
$emoticons = array(
  '[HAPPY]' => array(' :-) ', ' :) ', ' :o) '), //etc...
  '[SAD]'   => array(' :-( ', ' :( ', ' :-| ')
);
foreach ($emoticons as $emotion => $icons) {
  $string = str_replace($icons, " $emotion ", $string);
}
echo $string;

出力:

Lorem ipsum [HAPPY] dolor [SAD] samet

したがって、原則としてこれは機能します。ただし、次の 2 つの質問があります。

  1. ご覧のとおり、':-)' の代わりに ':-)' のように、配列内の各絵文字の周りにスペースを入れています。これにより、配列が読みにくくなっていると思います。スペースなしで顔文字を保存する方法はありますが、それでも $string と一致し、それらの周りにスペースがありますか? (そして、コードは今と同じくらい効率的ですか?)

  2. それとも、顔文字を 1 つの変数に入れ、スペースを爆発させて $string をチェックする方法はありますか? 何かのようなもの

    $emoticons = array( '[HAPPY]' => ">:] :-) :) :o) :] :3 :c) :> =] 8) =) :} :^)", '[SAD] ' => ":'-( :'( :'-) :')" //etc...

  3. str_replace はこれを行う最も効率的な方法ですか?

何百万もの文字列をチェックする必要があるため、処理時間を節約する最も効率的な方法を探しています:)

4

5 に答える 5

5

これは、CPANの Perl サードパーティRegexp::Assembleモジュールを使用したアイデアです。たとえば、次のプログラムがあるとします。

#!/usr/bin/env perl
use utf8;
use strict;
use warnings;

use Regexp::Assemble;

my %faces = (
    HAPPY => [qw¡ :-) :) :o) :-} ;-} :-> ;-} ¡],
    SAD   => [qw¡ :-( :( :-| ;-) ;-( ;-< |-{ ¡],
);

for my $name (sort keys %faces) {
    my $ra = Regexp::Assemble->new();
    for my $face (@{ $faces{$name} }) {
        $ra->add(quotemeta($face));
    }
    printf "%-12s => %s\n", "[$name]", $ra->re;
}

これは次のように出力されます。

[HAPPY]      => (?-xism:(?::(?:-(?:[)>]|\})|o?\))|;-\}))
[SAD]        => (?-xism:(?::(?:-(?:\||\()|\()|;-[()<]|\|-\{))

おそらく必要のない余分なものが少しあるので、それらは次のように削減されます。

[HAPPY]      => (?:-(?:[)>]|\})|o?\))|;-\}
[SAD]        => (?:-(?:\||\()|\()|;-[()<]|\|-\{

とか、ぐらい。これを Perl プログラムに組み込んで、余分なビットを削除できます。次に、右側をまっすぐに配置できますpreg_replace

私がそうした理由は、そこにあるものをエスケープすることを台無しにしたくなかったので、区切り文字としてuse utf8使用できるようにするためです。¡qw//

プログラム全体が Perl である場合は、これを行う必要はありません。Perl の最近のバージョンでは、これが自動的に行われることが既にわかっているからです。しかし、他の言語で使用するパターンを生成できるように、モジュールの使用方法を知っておくと役に立ちます。

于 2012-02-15T16:17:55.407 に答える
3

これは、あいまいテキストの一致と置換のためのツールである正規表現の優れたアプリケーションのように思えます。正確なテキストの検索と置換str_replaceのためのツールです。regexps を使用すると、「このように見えるテキスト」のクラス全体を検索できます。これ、受け入れる文字の種類、文字数、順序などに関して定義されています。

正規表現を使用すると...

  1. ワイルド\sカードは空白と一致するため、\s$emotion\s.

    (絵文字が文字列の末尾にある場合も考慮してください。つまり、that was funny lol :)絵文字の前後にスペースがあると常に想定できるとは限りません。これを処理する正規表現を作成できます。)

  2. リスト内の任意の絵文字に一致する正規表現を作成できます。|これは、記号として読み取ることができる代替記号 を使用して行いますOR。構文は(a|b|c)パターンaOR bORに一致しますc

    たとえば、(:\)|:-\)|:o\))のいずれかに一致します:),:-),:o)。's は正規表現内で特別な意味を持つため、エスケープする必要があったことに注意してください)(括弧はグループ化演算子として使用されます)。

  3. 時期尚早の最適化は諸悪の根源です。

    最も明白なことを最初に試してください。それが機能しない場合は、後で最適化できます(コードをプロファイリングして、これが実際に具体的なパフォーマンス上の利点をもたらすことを確認した後)。

正規表現を学習したい場合は、TextWrangler マニュアルの第 8 章を試してください。これは、正規表現の使用法と構文について非常に理解しやすい入門書です。

注: 私のアドバイスは、プログラミング言語に依存しません。私の PHP-fu は私の Python-fu よりもはるかに弱いので、サンプル コードを提供することはできません。:(

于 2012-02-15T15:19:43.343 に答える
2

イントロコメント:一度に1つの質問だけをしてください。あなたはより良い答えを得るでしょう。その次に、これまでに行ったメトリックを表示しないと、優れたパフォーマンスのアドバイスを得ることができません。

私があなたのコードから見ることができることから、あなたはあなたが節約できる文字列処理を2回行い、特定のスペースに置換を置くということです。最初に自分の定義で展開できます。

$emoticons = array(
  ' [HAPPY] ' => array(' :-) ', ' :) ', ' :o) '), //etc...
  ' [SAD] '   => array(' :-( ', ' :( ', ' :-| ')
);

foreach ($emoticons as $replace => $search)
{
  $string = str_replace($search, $replace, $string);
}

これにより、呼び出すたびにマイクロ秒の数分の1が節約され、おそらく気付かないほどのパフォーマンスが向上します。これは、おそらくこれをCで記述してコンパイルする必要があるという点に私を導きます。

Cに少し近いのは、一度コンパイルしてから再利用する正規表現を使用することです。これは、別の回答ですでに提案されています。ここでの利点は、同じ式を複数回実行する場合にPHPで実行できる最速の方法があり正規表現を事前に生成できるため、編集しやすい形式で保存できることです。次に、パフォーマンスをほとんど調整する必要がない場合に備えて、正規表現をキャッシュできます。

1.ご覧のとおり、配列内の各絵文字の周りに、「:-)」ではなく「:-)」のようにスペースを入れています。これにより、私の意見では配列が読みにくくなります。スペースなしで絵文字を保存する方法はありますが、それでも周囲にスペースがある$ stringと一致しますか?(そして今のコードと同じくらい効率的に?)

はい、これは可能ですが、構成データをさらに処理して置換データにする必要があるという意味で、より効率的ではありません。実際にどのような効率について話しているのかはわかりませんが、後で推測するので、答えは可能ですが、非常に特殊なユースケースには適していません。通常は編集しやすいものをお勧めします。複数のコンピューターに処理を分散させることで処理速度をかなり短縮できるため、処理速度を気にするよりも効率的に処理できると言えます。

2.または、絵文字を1つの変数に入れて、スペースを爆発させて$ stringと照合する方法はありますか?何かのようなもの

$emoticons = array( '[HAPPY]' => ">:] :-) :) :o) :] :3 :c) :> =] 8) =) :} :^)", '[SAD]' => ":'-( :'( :'-) :')" //etc...

もちろん、それは可能ですが、1と同じ問題が発生します。

3. str_replaceはこれを行う最も効率的な方法ですか?

さて、今あなたが提供したコードで、それはあなたが尋ねる唯一の方法です。あなたが私たちに話す代替手段がないので、それは少なくともあなたのために働いています、それは現時点であなたのためにそれをする最も効率的な方法です。だから今、はい。

于 2012-02-15T15:41:44.420 に答える
2

絵文字を置き換えたい $string がサイトの訪問者によって提供された場合 (コメントなどのユーザーの入力であることを意味します)、絵文字の前後にスペースがあることを伝える必要はありません。また、:-) と :-)) のように、非常に似ているが異なる顔文字が少なくとも 2 つあります。したがって、絵文字の配列を次のように定義すると、より良い結果が得られると思います。

$emoticons = array(
    ':-)' => '[HAPPY]',
    ':)' => '[HAPPY]',
    ':o)' => '[HAPPY]',
    ':-(' => '[SAD]',
    ':(' => '[SAD]',
    ...
)

そして、すべての検索/置換定義を入力するときは、:-)) を :-) に置き換える機会がないように、この配列を並べ替える必要があります。配列の値を長さでソートすれば十分だと思います。これは、str_replace() を使用する場合です。strtr() は、この長さによるソートを自動的に行います!

パフォーマンスが気になる場合は、strtr vs str_replaceを確認できますが、独自のテストを行うことをお勧めします ( $string の長さと検索/置換定義に関して異なる結果が得られる場合があります)。

最も簡単な方法は、「定義の検索」に末尾のスペースが含まれていない場合です。

$string = strtr( $string, $emoticons );
$emoticons = str_replace( '][', '', trim( join( array_unique( $emoticons ) ), '[]' ) );
$string = preg_replace( '/\s*\[(' . join( '|', $emoticons ) . ')\]\s*/', '[$1]', $string ); // striping white spaces around word-styled emoticons
于 2012-02-15T16:20:58.140 に答える
2

str_replace最初に、スペースを含む配列を使用して、最も単純な実装を試してみます。パフォーマンスが許容できない場合は、感情ごとに 1 つの正規表現を試してください。それは物事をかなり圧縮します:

$emoticons = array(
  '[HAPPY]' => ' [:=]-?[\)\]] ', 
  '[SAD]'   => ' [:=]-?[\(\[\|] '
);

それでもパフォーマンスが受け入れられない場合は、サフィックス ツリー ( http://en.wikipedia.org/wiki/Suffix_treeを参照) などのより洗練されたものを使用できます。これにより、すべての絵文字について文字列を 1 回だけスキャンできます。概念は単純です。ルートがスペースであるツリーがあり (絵文字の前にスペースを一致させたいため)、最初の子は ':' と '=' であり、次に ':' の子は ']' です。 ')'、'-' など。文字列を 1 文字ずつスキャンする単一のループがあります。スペースが見つかったら、ツリーの次のレベルに移動し、次の文字がそのレベルのノードの 1 つ (「:」または「=」) であるかどうかを確認し、そうであれば次のレベルに移動します。任意の時点で、現在の文字が現在のレベルのノードでない場合は、ルートに戻ります。

于 2012-02-15T15:26:35.887 に答える