【问题标题】:A more efficient string cleaning Regex in PHPPHP中更有效的字符串清理正则表达式
【发布时间】:2012-11-18 10:27:16
【问题描述】:

好的,我希望有人可以帮助我使用一点正则表达式。

我正在尝试清理字符串。

基本上,我是:

  1. 将除 A-Za-z0-9 之外的所有字符替换为替换字符。

  2. 用单个替换实例替换连续重复的替换。

  3. 从字符串的开头和结尾修剪替换。

示例输入:

(&&(%()$()#&#&%&%%(%$+-_狗跳过去日志*(&)$%&)#)@#%&)&^)@#)

所需输出:

The+dog+jumped+over+the+log

我目前正在使用这个非常混乱的代码,只是知道有一种更优雅的方式来完成这个......

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);
}

【问题讨论】:

  • 对于 1 和 2,您可以尝试用替换替换 [^A-Za-z0-9]+
  • 我讨厌 stackoverflow 强迫我选择一个答案......
  • 我认为将模式放在单独变量中的版本更具可读性。
  • 我为代码示例选择了 Botond Balázs 的答案。但我想拥抱/感谢 hakre 的深入解释和帮助。谢谢大家!

标签: php regex string clean-urls code-cleanup


【解决方案1】:

我不是“正则表达式忍者”,但我会这样做。

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] 匹配所有-字母数字字符
    • + 表示“匹配上一个或多个”
  • /[^A-Za-z0-9]+$/:
    • 和上面一样,除了$匹配字符串的结尾
  • /[^A-Za-z0-9]+/:
    • 和上面一样,除了它也匹配中间字符串

编辑: OP 是正确的,前两个可以替换为对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);
}

【讨论】:

    【解决方案2】:

    我不想听起来超级聪明,但我不会称它为 regex-foo。

    您所做的实际上几乎是正确的方向,因为您使用了preg_quote,许多其他人甚至不知道该功能。

    但是可能在错误的地方。错误的地方,因为您在字符类中引用字符,并且在正则表达式中引用的规则(相似但)不同。

    此外,正则表达式的设计考虑了您的情况。这可能是您寻找向导的部分,让我们看看一些选项如何使您的否定字符类更紧凑(我将生成保留以使其更明显):

    [^0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]
    

    有像 0-9A-Za-z 这样的结构可以准确地表示这一点。如您所见,- 是字符类中的一个特殊字符,它不是字面意思,而是具有一些从到到的字符:

    [^0-9A-Za-z]
    

    所以这已经更紧凑并且代表相同。还有像 \d\w 这样的符号在你的情况下可能很方便。但我暂时采用第一个变体,因为我认为它的作用已经很明显了。

    另一部分是重复。让我们看看,有+ 表示一个或多个。所以你想替换一个或多个不匹配的字符。您可以通过在应该匹配一次或多次的部分末尾添加它来使用它(默认情况下它是贪婪的,所以如果有 5 个字符,将采用这 5 个字符,而不是 4 个字符):

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

    我希望这会有所帮助。另一个步骤是也只删除开头和结尾的不匹配字符,但现在是清晨,我不太熟悉。

    【讨论】:

    • 很好的解释。对于提问者,我建议阅读“掌握正则表达式”一书。这让我大开眼界。
    • @BotondBalázs:非常正确。作为在线资源,我觉得regular-expressions.info 也不错。即使是关于正则表达式语法的 PHP 手册现在也得到了改进,过去它有点稀疏:php.net/manual/en/pcre.pattern.php
    • 作为 RegexBuddy 的在线(免费)替代品,我推荐 gskinner.com/RegExr - 尽管在功能方面没有什么能比 RegexBuddy 更好:)
    • 确实,这是一个非常有帮助和彻底的回应。谢谢你。关于您对 preg_quote 的评论,我需要使用它,因为正如我在问题中遗漏的那样,我必须能够动态添加可能是语法的“好的”字符。使用 preg_quote 逃逸的方式和地点是合适的?
    • 正如preg_quote 所写的,很高兴知道和使用。我认为它不会给您带来任何问题,只是想指出,在某些极端情况下,它可能不会根据需要引用 exactly 。但这并不意味着它会带来问题。
    猜你喜欢
    • 1970-01-01
    • 2011-01-15
    • 1970-01-01
    • 2010-10-12
    • 1970-01-01
    • 2020-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多