php正则表达式提取标记包含特定单词的匹配项

php正则表达式提取标记包含特定单词的匹配项,php,regex,preg-match-all,Php,Regex,Preg Match All,我有以下字符串: <product><name>Tea</name><price>12</price></product> <product><name>black coffee</name><price>23</price></product> <product><name>cheap black-coffee</name

我有以下字符串:

<product><name>Tea</name><price>12</price></product>
<product><name>black coffee</name><price>23</price></product>
<product><name>cheap black-coffee</name><price>44</price></product>
Tea12
黑咖啡
便宜的黑咖啡
我想抓住所有出现“咖啡”或“咖啡黑”的产品

我尝试了以下代码:

preg_match_all('/<product>(.*?)(black coffee|black-coffee)(.*?)<\/product>/is', $string, $result);
preg_match_all('/(.*)(黑咖啡|黑咖啡)(.*)/is',$string,$result);

但该代码合并了阵列中的两个产品。正如你所知,我对正则表达式一点也不熟悉

您需要使用否定的前瞻断言而不是
*?
,因为
*?
也将匹配
标记

<product>((?:(?!<\/?product).)*?)(black coffee|black-coffee)((?:(?!<\/?product).)*?)<\/product>

((?:(?!不要为此使用正则表达式;这只会给自己带来麻烦。请使用解析器。将所有捕获组转换为非捕获组,以避免不必要的捕获
$re = "/<product>(?:(?:(?!<\\/?product).)*?)(?:black coffee|black-coffee)(?:(?:(?!<\\/?product).)*?)<\\/product>/is";
$str = "<product><name>Tea</name><price>12</price></product>\n<product><name>black coffee</name><price>23</price></product>\n<product><name>cheap black-coffee</name><price>44</price></product>";
preg_match_all($re, $str, $matches);
print_r($matches[0])