PHP中更高效的字符串清理Regex

时间:2012-11-18 10:27:16

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

好吧,我希望有人可以用一点regex-fu来帮助我。

我正在尝试清理字符串。

基本上,我是:

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

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

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

  4. 示例输入:

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

    必需输出:

    在+狗+跃升+ +以上的+登录

    我目前正在使用这个非常混乱的代码,并且知道有一个更优雅的方法来实现这个....

    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 Master能否为我提供更简单/更有效的解决方案?


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

2 个答案:

答案 0 :(得分: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]匹配所有 - 字母数字字符
    • +表示“匹配之前的一项或多项内容”
  • /[^A-Za-z0-9]+$/
    • 与上述相同,但$匹配字符串的结尾
  • /[^A-Za-z0-9]+/
    • 与上面相同的内容,除了它匹配mid-string

编辑: 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);
}

答案 1 :(得分:2)

我不想听起来超级聪明,但我不会称它为正则表达式。

你所做的实际上是在正确的方向,因为你使用preg_quote,其他许多人甚至都不知道这个功能。

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

此外,正则表达式的设计与您的情况类似。这可能就是你寻找向导的部分,让我们看看如何使你的负面角色类更加紧凑(我让这一代人更加明确):

[^0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]

0-9A-Za-z之类的结构可以代表这一点。正如您所看到的,-是一个字符类中的特殊字符,它不是字面意思,而是具有从 - 到的一些字符:

[^0-9A-Za-z]

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

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

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

我希望这会有所帮助。另一个步骤就是在开头和结尾放下不匹配的字符,但是它早上很早就没那么流利了。