<h2>诊断</h2>
<p>首先,让我们来看看为什么你的代码不能工作。@jorijnsmit提供了它(并共享了一个<a href="https://stackoverflow.com/q/180986/11301900">useful answer</a>),不管字符在哪里,正则表达式都会匹配字符。让我们用一个更简单的例子来说明,我将贯穿始终:</p>
<p>我们想要匹配单词<code>'app'</code>和<code>'he'</code>,因此我们构造了一个与您的非常相似的regex。在</p>
<pre class="lang-py prettyprint-override"><code>strings_to_match = ['app', 'he']
match_pattern = '|'.join(strings_to_match) # "app|he"
</code></pre>
<p>我们用交替运算符连接要匹配的字符串,这样就可以开始了,对吧?感谢<a href="https://regex101.com" rel="nofollow noreferrer">regex101</a>的魔力,以下是将我们的模式应用于几个字符串(匹配项在方括号中)的结果:</p>
<ul>
<li><code>[he]llo</code></li>
<li><code>brot[he]r</code></li>
<li><code>[app]lication</code></li>
<li><code>[he]</code></li>
<li><code>[app]le</code></li>
<li>^{cd8}</li>
<li><code>[app]</code></li>
<li><code>[he]ll</code></li>
</ul>
<p>我们的模式在任何地方匹配字符串<code>'app'</code>和<code>'he'</code>,而我们只需要单词本身!在</p>
<hr/>
<h2>正则表达式解决方案</h2>
<p>我们能做些什么来解决这个问题?我们的第一个想法可能是将我们的模式改为<code>' app | he '</code>,这确实解决了<code>'application'</code>这样的字符串的问题。不幸的是,这不是万无一失的。该模式无法识别<code>'I downloaded an app.'</code>中的单词<code>'app'</code>,这对我们来说是完全有效的。幸运的是,regex正好有我们需要的解决方案:<a href="https://www.regular-expressions.info/wordboundaries.html" rel="nofollow noreferrer">Word boundaries</a>,由标记<code>'\b'</code>表示,其原理相当不言自明。在</p>
<p>以下是新模式<code>'\bapp\b|\bhe\b'</code>的一些结果:</p>
<ul>
<li><code>'[he]'</code></li>
<li><code>'apple'</code></li>
<li><code>'happier'</code></li>
<li><code>' [app] '</code></li>
<li><code>'hell'</code></li>
<li><code>'I downloaded an [app]!'</code></li>
</ul>
<p>正是我们所期待的!虽然它确实工作正常,但这种模式不必要地难以阅读。通过将所有子字符串放入<a href="https://www.regular-expressions.info/brackets.html" rel="nofollow noreferrer">non-capturing group</a>:<code>'\b(?:app|he)\b'</code>,我们只能使用一组单词边界标记。一个捕获组,嗯,分组并捕获正则表达式的一个子集。在本例中,组将返回与整个匹配项相同的结果。非捕获组消除了这种冗余,同时仍然允许我们在逻辑上分离表达式的一部分。在</p>
<p>下面是一个完整的程序,演示如何构建模式并将其用于熊猫系列:</p>
^{pr2}$
<p><code>print(match_res)</code>的输出:</p>
<pre class="lang-py prettyprint-override"><code>0 False
1 False
2 False
3 True
4 False
5 False
6 True
7 False
8 True
9 True
dtype: bool
</code></pre>
<hr/>
<h2>关于其他解决方案的几点注记</h2>
<h3>1.</h3>
<p><strong>请注意,这些方法只能匹配单词,不能匹配任意子字符串。因此,它们实际上并不是这个特定问题的有效解决方案,只是为了完整起见才在这里讨论。</strong></p>
<p>这与@FBruzzesi的解决方案相同,我们将其称为版本1。供参考:</p>
<pre class="lang-py prettyprint-override"><code># Convert string into list of strings
str_list = str_choice.split(|)
# Control if any word is in the sentence after splitting the sentence by space
df['has_match'] = df.apply(lambda r: [x for x in str_list if x in r['EmentaMateria'].split(' ')], axis=1)
#This will create a list of words you find, then you can filter only those which has a match
df = df[df.apply(lambda r: len(r['has_match'])>0, axis=1)]
</code></pre>
<p>当他们的解决方案收集所有匹配项时,我们只关心是否有匹配项。让我们看看他们的解决方案的重构版本,版本2:</p>
<pre class="lang-py prettyprint-override"><code>import pandas as pd
test_strs = ['hello', 'brother', 'application', 'he', 'apple', 'happier', 'app', 'hell', ' app ',
'I downloaded an app.']
test_series = pd.Series(data=test_strs)
strings_to_match = ['app', 'he']
series_split = test_series.str.split()
match_res = series_split.map(lambda curr_words: any((curr_sub in curr_words for curr_sub in strings_to_match)))
</code></pre>
<p>与版本1不同,版本2将<code>split()</code>操作的数量保持在最低限度,这是一个真正值得关注的问题(我估计整个列大约有8000000个<code>split()</code>操作)。由于迭代次数取决于要匹配的子字符串的数量,因此它应该更高效,而子字符串的数目通常应低于要检查的字符串中的单词数。在</p>
<h3>2.</h3>
<p>我看到了一些关于<code>regex</code>参数的提及,我觉得这些参数不清楚或有误导性。是的,传递<code>regex=False</code>将匹配一个文本字符串,不,仅仅更改参数不会使当前代码正常工作(为什么会这样呢?)。在</p>
<hr/>
<p>我希望这就是你在要求一个规范的答案时所想的那种事情。如果有任何不清楚的地方或您有任何进一步的问题,请告诉我:)</p>