【问题标题】:Check if a string contain multiple specific words检查字符串是否包含多个特定单词
【发布时间】:2013-04-07 12:26:59
【问题描述】:

如何检查一个字符串是否包含多个特定单词?

我可以使用以下代码检查单个单词:

$data = "text text text text text text text bad text text naughty";
if (strpos($data, 'bad') !== false) {
    echo 'true';
}

但是,我想添加更多单词来检查。像这样的:

$data = "text text text text text text text bad text text naughty";
if (strpos($data, 'bad || naughty') !== false) {
    echo 'true';
}

(如果找到这些单词中的任何一个,那么它应该返回 true)

但是,上面的代码不能正常工作。任何想法,我做错了什么?

【问题讨论】:

  • 如果所有个单词都在字符串中,或​​者找到一个个单词,函数是否应该返回true?
  • 如果找到了其中一个词,那么它应该返回true

标签: php


【解决方案1】:

为此,您需要Regular Expressionspreg_match 函数。

类似:

if(preg_match('(bad|naughty)', $data) === 1) { } 

你的尝试失败的原因

正则表达式由 PHP 正则表达式引擎解析。您的语法问题在于您使用了 || 运算符。这不是正则表达式运算符,因此它被视为字符串的一部分。

如上所述,如果它被视为您要匹配的字符串的一部分:'bad || naughty' 作为字符串,而不是表达式!

【讨论】:

  • 请注意,如果模式匹配给定的主题,preg_match 返回 int 值 1,而不是 true。将=== true 替换为=== 1!== 0。见php.net/manual/en/…
  • 感谢您的来信。我最初确实让它检查真实值而不是类型检查,但建议我编辑它以使用三等号运算符。
  • 如果性能很重要,通常最好避免使用 preg_match() 进行这种简单的字符串搜索,因为与 strpos() 等其他选项相比,它相当慢。另外可能值得指出的是,它匹配任何子字符串,不一定是整个单词(“badminton”也会返回 true)。
  • @christopher 如果坏了怎么办 |在其中,即 ba|d
  • 请注意,括号在此代码中用作模式分隔符,而不是作为捕获组。我不鼓励使用括号作为分隔符,因为它会在调试时欺骗开发人员的眼睛。
【解决方案2】:

你不能这样做:

if (strpos($data, 'bad || naughty') !== false) {

相反,您可以使用正则表达式:

if(preg_match("/(bad|naughty|other)/i", $data)){
 //one of these string found
}

【讨论】:

  • 这是非常好的 @christopher 示例没有工作,但你的工作: if(preg_match("/(bad|naughty|other)/i", $data)){ //其中一个字符串找到 }
  • 同意以上评论。谢谢老兄。
  • 这个有效,因为它添加了所需的分隔符。不区分大小写的可选“i”是一个不错的选择。接受的答案是有缺陷的。
【解决方案3】:

strpos 确实搜索您作为第二个参数传递的确切字符串。如果要检查多个单词,则必须使用不同的工具

正则表达式

if(preg_match("/\b(bad|naughty)\b/", $data)){
    echo "Found";
}

preg_match如果字符串中有匹配则返回1,否则返回0)。

多次 str_pos 调用

if (strpos($data, 'bad')!==false or strpos($data, 'naughty')!== false) {
    echo "Found";
}

爆炸

if (count(array_intersect(explode(' ', $data),array('bad','naugthy')))) {
    echo "Found";
}

对我来说,首选的解决方案应该是第一个。很明显,由于使用了正则表达式,可能效率不高,但它不会报告误报,例如,如果字符串包含单词 badmington

,它不会触发回显

如果有很多单词,正则表达式可能会成为创建的负担(尽管$regex = '/\b('.join('|', $badWords).')\b/';$regex = '/\b('.join('|', $badWords).')\b/';

第二个是直截了当的,但无法区分 badbadmington

如果字符串用空格分隔,第三个将字符串拆分为单词,制表符会破坏您的结果。

【讨论】:

  • 只是对 str_pos 的一个小修正:添加 || 而不是 or : if (strpos($data, 'bad')!==false || strpos($data, 'naughty')!== false) { echo "Found"; }
  • 只是对上面误导性更正的一个小的重新更正。使用 or 非常好,因为它用于此答案。
  • 作为记录,count() 调用不是必需的。如果array_intersect() 是一个非空数组,那么它将被评估为“真”。
【解决方案4】:

if(preg_match('[bad|naughty]', $data) === true) { }

以上说法并不完全正确。

“如果模式匹配给定的主题,preg_match() 返回 1,如果不匹配,则返回 0,如果发生错误,则返回 FALSE。”

所以应该是这样的:

if(preg_match('[bad|naughty]', $data)) { }

【讨论】:

  • if(preg_match('[bad|naughty]', $data) == true){} 所以这不是一个严格的比较...
  • == true 是不必要的语法。
  • 我发现使用 [] 作为模式分隔符会造成不必要的混淆/误导。我看到很多新开发人员未能理解作为字符类的方括号实际上是模式分隔符。为了清楚起见,我从不使用 []() 作为模式分隔符。
【解决方案5】:

substr_count()

我想用substr_count() 添加另一种方法(高于所有其他答案):

if (substr_count($data, 'bad') || substr_count($data, 'naughty')){
    echo "Found";
}

substr_count() 正在计算字符串出现的次数,所以当它为 0 时,你就知道它没有找到。 我会说这种方式比使用str_pos()(其中一个答案中提到过)更具可读性:

if (strpos($data, 'bad')!==false || strpos($data, 'naughty')!== false) {
    echo "Found";
}

【讨论】:

    【解决方案6】:

    你必须对每个单词进行解析。现在您正在检查是否有一个字符串说明

    'bad || naughty'
    

    不存在的。

    【讨论】:

      【解决方案7】:

      使用要测试的单词数组和array_reduce() 函数的简单解决方案:

      $words_in_data = array_reduce( array( 'bad', 'naughty' ), function ( $carry, $check ) use ( $data ) {
          return ! $carry ? false !== strpos( $data, $check ) : $carry;
      } );
      

      那么你可以简单地使用:

      if( $words_in_data ){
          echo 'true';
      }
      

      【讨论】:

      • 使用“函数式编程”来完成这项任务的缺点是您无法享受“提前返回”(短路)的好处。这实际上意味着您的迭代技术将继续迭代所有值,无论它是否找到符合条件的匹配项。在许多情况下,这是不受欢迎的行为。这不是对这个答案的攻击,这只是对研究人员的警告。易碎的foreach() 一样冗长,但效率/直接性更高。
      • 没问题@mickmackusa。但实际上,如果在字符串中找到任何单词,它不会检查其余的单词。我相信这几乎就像短路一样
      • 就效率/直接性而言,它“介于两者之间”。虽然它不会在每次迭代时继续调用strpos(),但它会不必要地迭代整个输入数组。换句话说,它对于非短路技术来说是“尽可能好”。最终,我认为没有任何令人信服的理由将这种冗长的技术与use() 一起使用,而不是简单的foreach()。如果开发人员想要适合if (multiNeedleSearch($needles, $haystack)) { 的整洁的东西,那么只需编写一个包含foreach() 的自定义函数。
      【解决方案8】:

      这是一个可以在不使用正则表达式的情况下执行此操作的函数,这可能会更慢。不要为任务传递单个字符串,而是传递一个数组,如

      if (strposMultiple($data, ['bad', 'naughty']) !== false) {
          //...
      }
      

      函数如下:

      function strposMultiple($haystack, $needle, $offset = 0) {
          if(is_string($needle))
              return strpos($haystack, $needle, $offset);
          else {
              $min = false;
              foreach($needle as $n) {
                  $pos = strpos($haystack, $n, $offset);
      
                  if($min === false || $pos < $min) {
                      $min = $pos;
                  }
              }
      
              return $min;
          }
      }
      

      【讨论】:

        猜你喜欢
        • 2013-12-23
        • 1970-01-01
        • 2011-05-20
        • 2023-04-01
        • 1970-01-01
        相关资源
        最近更新 更多