如果字符串包含子字符串数组中的一个子字符串,如何返回布尔值


How to return a boolean if a string contains one of an array of substrings?

我正在处理一个简单的函数,该函数在数组中循环,并且只有在数组的一个元素中找到给定的子字符串时才返回true

出于某种原因,我总是得到false。。。即使当CCD_ 3参数包含一个有效域时也是如此。例如:scoobydoo@domain1.com

function check_email($email) {
    $whitelist_domains = array(
        '@domain1.com',
        '@domain2.com',
        '@domain3.com'
    );
    $output = FALSE;
    foreach ($whitelist_domains as $domain) {   
        $pos = strpos( $email, $domain ); 
        if ( $pos ) {
            $output = TRUE;
        }
    }
    return $output;
}

如果找到域,就不会破坏循环,所以得到的实际上是仅检查LAST字符串的结果。只需在$output = TRUE; 之后添加break;

来自strpos:的官方文档

警告

此函数可能返回布尔值FALSE,但也可能返回计算结果为FALSE的非布尔值。请阅读布尔值可获取更多信息。使用===运算符测试此函数的返回值。

并确保在将$output设置为true后添加一个break。

这是一个使用===运算符的好函数,因为它可以确保值和类型相等(1==true,但1!==true

if (strpos( $email, $domain )!==false) {
    $output = TRUE;
}

更改

if ( $pos ) {

if ( $pos !== false) {

这是因为is strpos返回0,即使找到了字符串,也等于false。

以下是两种具有不同优势的直接/常用方法:

方法#1:非正则表达式方法

function check_email1($email){
    $whitelist_domains=['@domain1.com','@domain2.com','@domain3.com'];
    foreach($whitelist_domains as $domain){
        if(strpos($email,$domain)!==false){
            return true;  // allow quick return (exit loop & function asap)
        }
    }
    return false;  // default response
}

方法#2:正则表达式方法

function check_email2($email){
    $whitelist_pattern='/@(?:domain1'.com|domain2'.com|domain3'.com)$/';  // condense if possible /@domain[123]'.com$/
    return (bool)preg_match($whitelist_pattern,$email);  // convert 0 or 1 output to boolean (false/true)
}

演示链接

输入/函数调用

$emails=['user@domain1.com','bad@bad.com'];
foreach($emails as $email){
    echo "$email'n";
    var_export(check_email1($email));
    echo "'n";
    var_export(check_email2($email));
    echo "'n'n";
}

输出

user@domain1.com
true
true
bad@bad.com
false
false

优点/缺点

  • strpos()在大多数情况下都会优于regex函数。您的默认方法应该是使用字符串函数,并且只有在字符串函数效率较低或过于复杂而无法编码时才更改为regex。相关页面:PHP字符串函数和PHP中的正则表达式哪个更高效?

  • 与#2相比,在#1中循环$whitelist_domains会使代码块看起来更笨重(如果将模式直接写入preg_match(),则可以将其压缩为一行)。

  • 在处理strpos()时,有时会出现简单/常见的错误。这些错误可能包括:

    • if条件下不检查false
    • 按错误顺序写入haystackneedle
  • #2确实需要一些关于正则表达式(转义、字符类、替换项等)的知识,这对缺乏经验的程序员来说可能是一种威慑。根据您如何编写regex模式以及有多少域将被列入白名单,#2可能比#1更难维护。

  • #2的附加优点是能够通过$元字符检查domain.com子串是否出现在单词的末尾。因此,regex提供了更强的验证。

您应该更改您的代码:

function check_email($email) {
    $whitelist_domains = array(
        '@domain1.com',
        '@domain2.com',
        '@domain3.com'
    );
    foreach ($whitelist_domains as $domain) {   
        if ( strpos( $email, $domain ) !== false ) {
            return true;
        }
    }
    return false;
}

strpos文件

引用手册(http://php.net/manual/en/function.strpos.php):

!==也可以使用运算符。使用!=无法按预期工作因为"a"的位置为0。语句(0!=false)计算为false。

示例代码

<?php
$mystring = 'abc';
$findme   = 'a';
$pos = strpos($mystring, $findme);
// The !== operator can also be used.  Using != would not work as expected
// because the position of 'a' is 0. The statement (0 != false) evaluates 
// to false.
if ($pos !== false) {
     echo "The string '$findme' was found in the string '$mystring'";
         echo " and exists at position $pos";
} else {
     echo "The string '$findme' was not found in the string '$mystring'";
}
?>