簡體   English   中英

正則表達式匹配包含特定單詞的句子,如果包含另一個特定單詞則放棄匹配

[英]Regular expression to match sentence containing specific words and discarding the match if it contains another specific word

問題就如標題所說。 可能嗎

例如,我要搜索兩個單詞: apple, orange和一個使整個句子錯誤的單詞: box所以表達式應該接受這個句子: One orange and one apple但將這個One orange and one apple丟棄orange and apple within a box

我已經考慮了一段時間,但找不到任何解決方案。

您可以使用正向正向來匹配包含appleorange字的字符串,如下所示:

(?=.*(orange|apple))

並且可以使用否定的前瞻來放棄匹配項(如果匹配項中包含這樣的box詞),

(?!.*box)

因此,正則表達式變成了這個,

^(?=.*(orange|apple))(?!.*box).*$

這是相同的演示

如果您可以提供使用的語言,我也應該可以提供示例代碼。

編輯:

萬一您使用的是當今最熱門的python語言(盡管我的主要語言是Java),以下是相同的示例代碼,

import re
strArr = ['One orange and one apple','One apple','One orange','orange and apple within a box','One apple and box','One orange and box','This contains none of accepted words so it doesn\'t match']
for x in strArr:
    print (x + ' --> ', end="")
    print (bool(re.match('^(?=.*(orange|apple))(?!.*box).*$', x)))

首先可以使用否定的lookahead 但是,它太昂貴而無法使用。 這是您要完成一項家庭作業或解決您正在濫用的系統所施加的某種愚蠢限制的事情。

也就是說,請考慮以下內容:

我想在字符串的任何地方找到“橙色”一詞。

通常,您可以通過執行以下操作來利用正則表達式搜索:

/orange/

但是,您也可以通過在單詞之前插入“ match any”模式來將搜索與字符串的開頭聯系起來:

/^.*orange/

(請注意,這兩個示例目前都不需要橙色作為單詞。“ storange”之類的東西會匹配。將其保存以備后用。)

您可以用蘋果做同樣的事情,但是如何將它們綁在一起呢?

一種簡單的方法(適用於很多引擎,但可能效果不佳)只是說明兩種可能性:

我想找到單詞“ orange”,后跟任意數量的字符,后跟單詞“ apple”,或單詞“ apple”,后跟任意數量的字符,后跟單詞“ orange”。

這是一個交替,這是| (豎線)在正則表達式中。 有時,您可能需要轉義正則表達式引擎的豎線(基本與擴展)。 在某些其他時間,您可能必須對命令行解析器進行轉義。 因此,根據您使用正則表達式的方式,可能必須編寫| \\\\\\\\| 或介於兩者之間。

但是,子模式很簡單:

/orange.*apple/
/apple.*orange/

因此,首先將它們替換為非捕獲組(如果可能!檢查您的文檔,如果需要,請使用捕獲組。),如下所示:

/(orange.*apple|apple.*orange)/

然后在前面添加“ tie to string開頭”:

/^.*(orange.*apple|apple.*orange)/

現在,您可以匹配同時包含兩個單詞的文本。

最后,您可以利用否定前瞻的功能來阻止單詞“ box”。 為此,請使用特殊的語法,該語法可能有所不同,但可能與(?! ... )接近(?! ... )在本例中, ...是“ box”)。

接下來,我不想看“盒子”一詞。

是這樣的正則表達式:

/(?!box)/

但是對於您來說,您想說:

我不想在以下文本中的任何地方看到“盒子”一詞。

這是另一個“任何字符”的特殊之處:

/(?!.*box)/

現在,如何在現有模式中使用它? 超前(和“向后看”)都是零寬度的斷言 這意味着它們可能會失敗,因為它們是斷言,但是它們消耗零個輸入字符(零寬度)。 因此,您要做的就是注意放置它們的位置,因為它們會在與之相對應的任何地方准確地聲明它們。

對於這種情況,我認為您想在一開始就做出一個簡單的斷言:“單詞框不出現”,然后進行其他匹配:

我想找到沒有單詞“ box”的行,但是包含... apple ... orange等。

您可以通過將錨點放到起點之后的前瞻位置來實現:

/^(?!.*box).*(apple.*orange|orange.*apple)/

這轉化為

At start of string,
 - confirm "box" does not appear in the line
 - match any character any number of times,
 - then either
   - match "apple", 
   - followed by any chars, any number of times
   - then "orange"
 - or
   - match "orange"
   - followed by any chars, any number of times
   - then "apple"

還有其他幾種方法可以解決此問題。 但是您需要注意性能 當您進行前瞻時,您正在邀請對該字符串進行另一次掃描。 因此,如果您的前瞻中帶有*+ ,則可能會一遍又一遍地重新掃描相同的文本。 這會使您放慢速度,這就是為什么我建議在開始時先行提前的原因。 您要么成功一次,要么立即失敗。

同樣,單詞之前和之間的.*也是潛在問題。 現代引擎通常足夠聰明,可以解決這個問題,但是某些數據庫引擎不是很聰明。 請注意:請進行一些性能測試,並使用遺漏的單詞和重復的單詞(蘋果...蘋果...橙色,蘋果...橙色...橙色)以確保性能還可以。 (在這種情況下,“ ...”表示200個隨機單詞。)

最后,考慮一下您希望單詞成為多大的單詞 正則表達式中有一種特殊的語法,該語法可能不存在或因引擎而異。 通常, 單詞邊界斷言的拼寫為\\b ,例如\\bapple\\b但是您可能必須寫\\yapple\\y\\mapple\\M\\<apple\\>甚至是[[:<:]]apple[[:>:]] \\yapple\\y [[:<:]]apple[[:>:]] 檢查您的文檔。

最后,請考慮使用正向先行是另一種方法,當您有互斥的替代項時,可以處理替代項。 代替apple.*orange|orange.*apple構造,您可以僅在模式的開頭使用兩個正向超前表達式。 這具有明確的性能含義,因為這兩個表達式表示對文本進行兩次掃描。 它確實簡化了正則表達式的構造,如果您需要兩個以上的單詞,尤其是要以編程方式生成模式,這可能是個問題:

/^(?!.*box)(?=.*apple)(?=.*orange)./

. 最后只是強迫一個角色參與。 這個表情說

我想要一個不包含單詞“ box”,不包含“ apple”和不包含“ orange”的行。

您可以看到如何用更多的單詞來擴展它,但是請注意,每次您執行?=.*您都在重新掃描文本。 如果您的文本項不超過80個字符,則可能不會在乎,但是,如果您要搜索成千上萬個字符以尋找可能僅相隔幾個字符的單詞,則以前的版本會更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM