4

さて、私は誰かが少しの正規表現で私を助けてくれることを望んでいました.

文字列をクリーンアップしようとしています。

基本的に、私は:

  1. A-Za-z0-9 を除くすべての文字を置換で置き換えます。

  2. 置換の連続する複製を置換の単一インスタンスに置換します。

  3. 文字列の最初と最後から置換をトリミングします。

入力例:

( && (%()$( )#& #&%&% %(%$ +-_犬が丸太を飛び越えた*(&)$%& )#)@#%&)&^)@# )

必要な出力:

The+dog+jumped+over+the+ログ

私は現在、この非常に混乱したコードを使用していますが、これを達成するためのはるかにエレガントな方法があることを知っています....

function clean($string, $replace){

    $ok = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
    $ok .= $replace;
    $pattern = "/[^".preg_quote($ok, "/")."]/";

    return trim(preg_replace('/'.preg_quote($replace.$replace).'+/', $replace, preg_replace($pattern, $replace, $string)),$replace);
}

Regex-Fu マスターは、よりシンプルで効率的なソリューションを提供してくれますか?


Botond Balázs と hakre によって提案および説明された、はるかに優れたソリューション:

function clean($string, $replace, $skip=""){
    // Escape $skip
    $escaped = preg_quote($replace.$skip, "/");

    // Regex pattern
    // Replace all consecutive occurrences of "Not OK" 
    // characters with the replacement
    $pattern = '/[^A-Za-z0-9'.$escaped.']+/';

    // Execute the regex
    $result = preg_replace($pattern, $replace, $string);

    // Trim and return the result
    return trim($result, $replace);
}
4

2 に答える 2

2

私は「正規表現の忍者」ではありませんが、これを行う方法は次のとおりです。

function clean($string, $replace){
    /// Remove all "not OK" characters from the beginning and the end:
    $result = preg_replace('/^[^A-Za-z0-9]+/', '', $string);
    $result = preg_replace('/[^A-Za-z0-9]+$/', '', $result);

    // Replace all consecutive occurrences of "not OK" 
    // characters with the replacement:
    $result = preg_replace('/[^A-Za-z0-9]+/', $replace, $result);

    return $result;
}

これはもっと単純化できると思いますが、正規表現を扱うときは、巧妙であることや超最適なコードを書くことよりも、明快さと読みやすさが重要になることがよくあります。

それがどのように機能するか見てみましょう:

  • /^[^A-Za-z0-9]+/:
    • ^文字列の先頭に一致します。
    • [^A-Za-z0-9]英数字以外のすべての文字に一致
    • +「前のものの1つ以上に一致する」を意味します
  • /[^A-Za-z0-9]+$/:
    • 上記と同じです$が、文字列の末尾に一致します
  • /[^A-Za-z0-9]+/:
    • 上記と同じですが、文字列の途中にも一致します

編集: OPは、最初の2つを次の呼び出しに置き換えることができるというのは正しいですtrim():

function clean($string, $replace){
    // Replace all consecutive occurrences of "not OK" 
    // characters with the replacement:
    $result = preg_replace('/[^A-Za-z0-9]+/', $replace, $result);

    return trim($result, $replace);
}
于 2012-11-18T10:37:44.327 に答える
2

超賢いとは言いたくありませんが、それを regex-foo とは呼びません。

を使用しているため、実際にはほとんど正しい方向に進んでいますがpreg_quote、他の多くの人はその機能に気づいていません。

しかし、おそらく間違った場所にあります。文字クラス内の文字を引用し、正規表現で引用するための規則が (似ていますが) 異なるため、間違った場所です。

さらに、正規表現は、あなたのようなケースを念頭に置いて設計されています。それはおそらくウィザードを探す部分です。負の文字クラスをよりコンパクトにする方法をいくつか見てみましょう(これをより見やすくするために世代を除外しています):

[^0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]

のような構造があり、0-9それはまさにそれを表すことができます。ご覧のとおり、 は文字クラス内の特殊文字であり、リテラルを意味するのではなく、~から~までのいくつかの文字を持つことを意味します。A-Za-z-

[^0-9A-Za-z]

したがって、それはすでによりコンパクトであり、同じことを表しています。あなたの場合に便利な\dandのような表記法もあります。\wしかし、最初の変種について少し触れておきます。なぜなら、それが何をするかはすでにかなり目に見えると思うからです。

他の部分は繰り返しです。見てみましょう、+これは 1 つ以上を意味します。したがって、1 つ以上の一致しない文字を置き換えたいとします。1回以上一致する必要がある部分の最後に追加して使用します(デフォルトでは貪欲であるため、5文字ある場合、4文字ではなく5文字が取得されます):

[^0-9A-Za-z]+

これがお役に立てば幸いです。別のステップとして、一致しない文字を最初と最後に削除することもできますが、早朝であり、私はそれが得意ではありません。

于 2012-11-18T10:38:07.687 に答える