2014-06-10 59 views
0

我有以下代码:PHP检查字符串中的字符,而不foreach循环

$wordsArray = ... 
foreach ($wordsArray as $word) 

    if (strpos($string, $word) !== FALSE) { 
     echo "Word found! Handle this a certain way" } 
    } 

} 

不幸的是,这样一个大阵的话(可能接近100),环太慢尤其是当我传递了数千个字符串到这个函数,并且运行这个foreach循环几千次。我怎样才能加快这个过程,或者重构我的代码,这样我就不需要遍历我的数组了,而是使用字符串本身并检查它的任何子字符串是否在我的数组中找到?我需要使我的代码的这部分更有效率。

此外,是什么让这更困难的是,每个字符串没有空格。相反,采取下面的例子:

传递的字符串: “Hereissomerandomsentence” 词

阵列:( '一些', '是', '的');

我的脚本会返回Word,因为“一些”,但我想找到一个更快的方式来做到这一点。

+0

“不需要遍历我的数组字符,而是使用字符串本身,并检查是否在我的数组中找到它的任何子字符串”---为什么你认为'2 + 3'是快于“3 + 2”? – zerkms

+0

可悲的事实是,使用foreach和in_array比使用声明或匿名函数的array_walk快。你到底在做什么?试图找到坏词? – Ohgodwhy

+0

这个问题似乎是离题,因为它是关于改善工作代码,并可能更适合http://CodeReview.stackexchange.com/ –

回答

1

简单但也不容易。下面是使用preg_match_all和简单的正则表达式作为一个例子一些代码:

// Set the string. 
$string = 'Hereissomerandomsentence'; 

// Set the words array. 
$wordsArray = array('some', 'are', 'the'); 

// Set the regex pattern. 
$regex_pattern = '/(?:' . implode('|', $wordsArray) . ')/i'; 

// Run a regex to get the value between the link tags. 
preg_match_all($regex_pattern, $string, $matches); 

// Return the results. 
echo '<pre>'; 
print_r($matches); 
echo '</pre>'; 

,这里是结果:

Array 
(
    [0] => Array 
     (
      [0] => some 
     ) 

) 

但是,当我说这是不容易的,缺乏的空间,可能会导致thenthe等匹配。请记住,电脑无法阅读。这都是模式逻辑。所以,如果我添加thenare的例子字符串是这样的:

// Set the string. 
$string = 'Hereissomerandomsentencethenhereweare'; 

结果反映thenthe被拾起:

Array 
(
    [0] => Array 
     (
      [0] => some 
      [1] => the 
      [2] => are 
     ) 

) 

编辑:楼主问了一个fair-但在评论中的复杂问题:

如果我只想要一个单词前面有一个单词还是某个单词?对于 例如,使用相同的测试字符串,你怎么能够改变正则表达式 通过 then前面时isthe时之前只包括some,并通过are“我们”先当?因此,对于您的示例, 输出将仅为'some'和are

你所要求做的是复杂的,但可行使用“Lookarounds” as explained on this site

下面是一个使用上面的代码示例:

$string = 'Hereissomerandomsentencethenhereweare'; 

// Set the regex pattern. 
$regex_pattern = '/(?<=is)some|(?<=then)the|(?<=we)are/i'; 

// Run a regex to get the value between the link tags. 
preg_match_all($regex_pattern, $string, $matches); 

// Return the results. 
echo '<pre>'; 
print_r($matches); 
echo '</pre>'; 

,其结果将是为你期望它:

Array 
(
    [0] => Array 
     (
      [0] => some 
      [1] => are 
     ) 

) 

这里是该正则表达式的说明/(?<=is)some|(?<=then)the|(?<=we)are/i

  • 开头和结尾的斜线(/)只是分隔符。
  • |字符是简单的和OR之间的条件。
  • 现在在OR条件之间是什么样的模式。

现在让我们以第一个(?<=is)some为例。

  • (?<=[word in here])是一个“Lookbehind”,意思是:只有在这个词前面有这个单词时,才会捕获这个单词。在这种情况下的字是is
  • 下面的单词是some
  • 所以这一切都增加到:只匹配some如果前面有is。然后the只有前面有then。然后are只有前面有we

现在知道这里有一个模式可能可能会创建一个多维数组,它可以为单词设置逻辑,以便仅在被另一个单词前面检查时检查。然后循环创建一堆正则表达式。但这是一项重大任务。

但至少现在你知道这个任务的正则表达式的基本知识!

+0

但是这里的问题是性能,而不是代码本身的质量。你能在这里提供一些基准吗? – Ohgodwhy

+0

@Ohgodwhy“你能在这里提供一些基准吗?”不是。为什么?原始海报想要做的概念将如所呈现的那样成为资源消耗。而设计一个更快的解决方案意味着重构这里没有提供的代码。 – JakeGould

+0

这很酷!但为什么它会输出每个匹配数组两次?我有点困惑。感谢你! @JakeGould – user3692430

2

会有一些环路参与,不管你喜欢还是不喜欢,但是当你切换到正则表达式,而不是一些优化可能是可行的:

$re = '/(?:' . join('|', array_map(function($word) { 
    return preg_quote($word, '/'); 
}, $wordsArray)) . ')/'; 

if (preg_match_all($re, $string, $matches)) { 
    // hurray! 
    print_r($matches[0]); 
} 
+0

“选择的表达式使用'\ b'(单词边界)断言来确保(在某种程度上)它只匹配整个单词。”这与原始海报询问关于字符串的内容没有像'这里有一些随机的句子“,”而且,更麻烦的是每个字符串都没有空格。“这绝对不行。 – JakeGould

+1

@JakeGould不知何故,我明白了与之相反的:)更新。 –

1
  • 排序保存潜在的下属字阵列可以在$ string中找到 。
  • 考虑一个由起始字母组织的多维数组;制作一个潜在的匹配字典,而不是使用一个巨大的,未排序的数组。
  • 将$ string的副本剪切成单个字符,解析它。
  • 知道在哪个索引处可以找到哪些字符。
  • 将这些字符放入一个集合中,以便您只使用唯一的 字符。
  • 检查每个独特的字符。如果 阵列中的从属单词不以这些唯一字符之一开头,或者保留这些字符,则可以将其作为潜在匹配丢弃。

使用这样的想法,可以减少所需的比较次数。通过减小潜在解决方案的大小,您可能可以加快匹配速度。

为了让这些缩减技术显示出它们的价值,潜在的匹配数组需要很大。也就是说,您节省的处理时间将需要超过处理时间花费在切除不太可能的匹配上。

在所提供的样本串,字母表中使用这样的: b 的C 1 d 1 Ë11 ˚F 克 H 3 I 1 Ĵ ķ 升 米2 N 4 O 2 p q ,R 4 第3 吨2 ù v 瓦特1 x y z。

所以,根本没有使用26个13个字母。有一半的信件没有发生。另外,e的出现几乎是其较接近的竞争对手的3倍:h,n和r。这意味着消除他们如何开始下属的话可能会减少时间。