检查字符串是否包含数组中的值

103

我正在尝试检测一个字符串是否至少包含一个存储在数组中的URL。

以下是我的数组:

$owned_urls = array('website1.com', 'website2.com', 'website3.com');

这个字符串是由用户通过PHP提交的。在确认页面上,我想检查输入的URL是否在数组中。

我尝试了以下操作:

$string = 'my domain name is website3.com';
if (in_array($string, $owned_urls))
{
    echo "Match found"; 
    return true;
}
else
{
    echo "Match not found";
    return false;
}
无论输入什么,返回的都是“未找到匹配项”。这种做法正确吗?
15个回答

114
试试这个。
$string = 'my domain name is website3.com';
foreach ($owned_urls as $url) {
    //if (strstr($string, $url)) { // mine version
    if (strpos($string, $url) !== FALSE) { // Yoshi version
        echo "Match found"; 
        return true;
    }
}
echo "Not found!";
return false;

如果你想要进行不区分大小写的检查,可以使用stristr()stripos()

8
从手册中翻译得到:注意:如果你只想确定一个特定的针(needle)是否出现在字符串(haystack)中,请使用更快且占用更少内存的函数strpos()。 - Yoshi
7
如果用户输入了像site3.com这样的域名,这个方法就不起作用了。它会匹配到本不应该匹配到的mysite3.com - billyonecan
只要将URL限制在2或3个预设的URL上,它就可以正常使用。 - danyo

40

如果你只想在数组中查找字符串,那么这将容易得多。

$array = ["they has mystring in it", "some", "other", "elements"];
if (stripos(json_encode($array),'mystring') !== false) {
echo "found mystring";
}

2
你的输入数组实际上是一个字符串。 - Burgi
4
我认为这是最佳答案,但由于代码中的简单错误没有得到赞同。 @Burgi 我编辑了答案,现在它是一个数组甚至包含多个子数组,他的方法仍然非常有效!! - Tarik
这个功能很好,但它没有告诉你数组匹配的是哪个键。 - ahinkle
5
如果您在检查之前要将数组转换为字符串,为什么不直接使用implode呢?不使用json_encode()的一个好理由是,如果数组中有json_encode()将转义或改变的字符,则存在变异风险。这种变异风险足以阻止我们作为一种常规工具推荐这种技术。失败演示:https://3v4l.org/RjPbX - mickmackusa
1
@AutoBaker 和 @mickmackusa,我亲自测试过了,implode 函数是不起作用的。我不知道你们的编辑是什么,但可能已经被还原了。无论如何,仅仅将 json_encode($array) 替换为 implode(" ", $array) 是不足以使其正常工作的,至少根据我的测试结果来看。使用 json_encode 仍然是最好的解决方案。 - Studocwho
显示剩余2条评论

28

试试这个:

$owned_urls= array('website1.com', 'website2.com', 'website3.com');

$string = 'my domain name is website3.com';

$url_string = end(explode(' ', $string));

if (in_array($url_string,$owned_urls)){
    echo "Match found"; 
    return true;
} else {
    echo "Match not found";
    return false;
}

- 感谢


10
假设这些字符串是由空格分隔的。例如,它将无法处理以下字符串“My url is https://website3.com”。 - Елин Й.
6
甚至对于“我拥有website3.com域名”,它也不起作用。这假设字符串位于末尾,但在处理用户提交的文本时,你无法做到这一点。 - Samuël Visser
我同意其他两位评论者对输入数据假设过多的看法。这不是研究人员可以依赖的好答案,因为它在功能上很狭窄。此外,这个答案缺少教育性的解释。"试试这个"的答案错失了向成千上万的研究人员进行教育/授权的机会。 - mickmackusa
"end" 函数需要一个数组引用作为其输入参数,最好将 explode(' ', $string) 的结果分配给一个变量,然后将其提供给 end($yourArray)。祝好! - funder7

26

很好,我有一个疑问...这个可以很好地匹配字符串的URL...我有一个字符串 $string = 'you-are-nice'; $string2 = 'you-are-nicer'; 我的$match = 'nice';我需要匹配单词“nice”,即使我的匹配字符串是“nice”,也不要匹配“nicer”。 - Srinivas08
@Srinivas08 考虑单词边界是一个合理的考虑,但不能用 str_replace() 实现。 - mickmackusa
1
开发人员不应该实现这种简洁技术的最主要原因是因为没有办法“提前返回”。换句话说,在进行替换后,绝对没有理由继续搜索替换项,所以该过程应该停止——但它无法停止。对于所有需要寻找二进制“找到”或“未找到”结果的任务,不应使用此技术,因为它会进行无用的额外迭代。 - mickmackusa

10

我认为更快的方法是使用preg_match函数。

$user_input = 'Something website2.com or other';
$owned_urls_array = array('website1.com', 'website2.com', 'website3.com');

if ( preg_match('('.implode('|',$owned_urls_array).')', $user_input)){
    echo "Match found"; 
}else{
    echo "Match not found";
}

4
感谢您提供这段代码片段,它可能会提供一些有限的、即时的帮助。一份适当的解释将大大提高其长期价值,因为它可以展示为什么这是一个好的解决方案,并使其更有用于未来有类似问题的读者。请编辑您的答案添加一些解释,包括您所做的假设。参考链接 - Alper t. Turker
为了更加安全,必须在模式中转义点:addcslashes(implode('|', $owned_urls_array, '.')) - Rey0bs
1
比起 strpos,代码量少了很多,但绝对慢得多。 - hndcrftd
1
正则表达式在与 strpos() 相比的对决中会更慢。我认为使用 preg_ 进行这种类型的任务的唯一原因是如果您想要包括单词边界以提高准确性。不要使用 addcslashes() 来转义正则表达式中的特殊字符,preg_quote() 是专门设计来处理这个必要性的。 - mickmackusa
1
此外,捕获组在模式中是无用的。 - mickmackusa

8
$string = 'my domain name is website3.com';
$a = array('website1.com','website2.com','website3.com');

$result = count(array_filter($a, create_function('$e','return strstr("'.$string.'", $e);')))>0; 
var_dump($result );

输出

bool(true)

4
供参考:create_function在PHP 7.2中已被弃用。 - Darryl E. Clarke
这个答案缺少教育性的解释。PHP手册指出,为了提高效率,不应使用strstr()来检查一个字符串是否存在于另一个字符串中,而是推荐使用strpos()。可以删除count()>0,并在array_filter()之前添加(bool),将空/非空数组转换为false/true - mickmackusa

6

以下是一个小型函数,它可以在给定的字符串中搜索数组中的所有值。我在我的网站上使用它来检查访问者的IP是否在某些页面上我的允许列表中。

function array_in_string($str, array $arr) {
    foreach($arr as $arr_value) { //start looping the array
        if (stripos($str,$arr_value) !== false) return true; //if $arr_value is found in $str return true
    }
    return false; //else return false
}

如何使用

$owned_urls = array('website1.com', 'website2.com', 'website3.com');

//this example should return FOUND
$string = 'my domain name is website3.com';
if (array_in_string($string, $owned_urls)) {
    echo "first: Match found<br>"; 
}
else {
    echo "first: Match not found<br>";
}

//this example should return NOT FOUND
$string = 'my domain name is website4.com';
if (array_in_string($string, $owned_urls)) {
    echo "second: Match found<br>"; 
}
else {
    echo "second: Match not found<br>";
}

示例:http://phpfiddle.org/lite/code/qf7j-8m09


1
它区分大小写,如果需要不区分大小写的版本,请使用stripos - hndcrftd

4
你可以使用implode函数将数组值与分隔符(|)连接起来,然后使用preg_match搜索该值。
这是我想到的解决方案...
$emails = array('@gmail', '@hotmail', '@outlook', '@live', '@msn', '@yahoo', '@ymail', '@aol');
$emails = implode('|', $emails);

if(!preg_match("/$emails/i", $email)){
 // do something
}

preg_match() 对于在合并后进行搜索是不必要的开销。没有理由不使用具有相同效果的 stripos()。我不赞成这种技术--它比必要的工作更努力,并且如果 $emails 字符串包含正则表达式引擎中具有特殊含义的字符,则存在破坏的风险。 - mickmackusa

3
如果你的$string始终保持一致(即域名总是在字符串末尾),则可以使用explode()end(),然后使用in_array()检查是否匹配(如@Anand Solanki在他们的答案中所指出的)。
如果不是这样,最好使用正则表达式从字符串中提取域,并使用in_array()检查是否匹配。
$string = 'There is a url mysite3.com in this string';
preg_match('/(?:http:\/\/)?(?:www.)?([a-z0-9-_]+\.[a-z0-9.]{2,5})/i', $string, $matches);

if (empty($matches[1])) {
  // no domain name was found in $string
} else {
  if (in_array($matches[1], $owned_urls)) {
    // exact match found
  } else {
    // exact match not found
  }
}

上述表达可能需要改进(我在这个领域并不特别了解)

这里是演示


在正则表达式模式中,字面点必须被转义(除非在字符类中)。\w = [A-Za-z0-9_]。可以将preg_match()调用本身放置在第一个if内部,以避免进行empty()函数调用。 - mickmackusa

2
你正在将整个字符串与数组的值进行比较,因此输出始终为“false”。 在这种情况下,我同时使用了array_filter和strpos。
<?php
$urls= array('website1.com', 'website2.com', 'website3.com');
$string = 'my domain name is website3.com';
$check = array_filter($urls, function($url){
    global $string;
    if(strpos($string, $url))
        return true;
});
echo $check?"found":"not found";

1
“global” 可以被使用 “use()” 替代。 - mickmackusa

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接