我想知道在 python 或 perl 中是否有任何方法可以構建一個正則運算式,您可以在其中定義一組選項,最多可以按任何順序出現一次。因此,例如,我想要 的衍生物foo(?: [abc])*,其中a,b,c只能出現一次。所以:
foo a b c
foo b c a
foo a b
foo b
都是有效的,但是
foo b b
不會是
uj5u.com熱心網友回復:
您可以將此正則運算式與捕獲組和負前瞻一起使用:
對于Perl,您可以將此變體與前向參考一起使用:
^foo((?!.*\1) [abc]) $
正則運算式演示
正則運算式詳情:
^: 開始foo: 比賽foo(: 開始一個捕獲組 #1(?!.*\1):否定前瞻斷言我們在輸入中的任何位置都與捕獲組#1 中的內容不匹配[abc]: 匹配一個空格后跟aorb或c
):結束捕獲組#1。重復此組 1 次以上$: 結尾
正如前面提到的,這個正則運算式使用了一個稱為前向參考的特性,它是對稍后出現在正則運算式模式中的組的反向參考。JGsoft、.NET、Java、Perl、PCRE、PHP、Delphi 和 Ruby 允許前向參考,但 Python 不允許。
這是不使用前向參考的Python 相同正則運算式的解決方法:
^foo(?!.* ([abc]).*\1)(?: [abc]) $
在這里,我們在重復組之前使用負前瞻來檢查匹配是否有任何允許的子字串重復,即[abc].
正則運算式演示 2
uj5u.com熱心網友回復:
您可以斷言右邊的空格和字母的第二個匹配項沒有匹配項:
foo(?!(?: [abc])*( [abc])(?: [abc])*\1)(?: [abc])*
foo字面匹配(?!負前瞻(?: [abc])*匹配空格和 ab 或 c 的可選重復( [abc])捕獲組,用于與相同的反向參考進行比較(?: [abc])*再次匹配一個空格和 ab 或 c\1對組 1 的反向參考
)關閉前瞻(?: [abc])*匹配可選的重復或空格和 ab 或 c
正則運算式演示
如果不想只匹配 foo,則可以將量詞更改為 1 或多個 (?: [abc])
perl 中的一個變體重用第一個子模式 using (?1)which 指的是捕獲組([abc])
^foo ([abc])(?: (?!\1)((?1))(?: (?!\1|\2)(?1))?)?$
正則運算式演示
uj5u.com熱心網友回復:
如果它不必是正則運算式:
import collections
# python >=3.10
def is_a_match(sentence):
words = sentence.split()
return (
(len(words) > 0)
and (words[0] == 'foo')
and (collections.Counter(words) <= collections.Counter(['foo', 'a', 'b', 'c']))
)
# python <3.10
def is_a_match(sentence):
words = sentence.split()
return (
(len(words) > 0)
and (words[0] == 'foo')
and not (collections.Counter(words) - collections.Counter(['foo', 'a', 'b', 'c']))
)
# TESTING
#foo a b c True
#foo b c a True
#foo a b True
#foo b True
#foo b b False
或者使用集合和海象運算子:
def is_a_match(sentence):
words = sentence.split()
return (
(len(words) > 0)
and (words[0] == 'foo')
and (
(s := set(words[1:])) <= set(['a', 'b', 'c'])
and len(s) == len(words) - 1
)
)
uj5u.com熱心網友回復:
您可以使用對先前捕獲的組的參考來執行此操作。
foo(?: ([abc]))?(?: (?!\1)([abc]))?(?: (?!\1|\2)([abc]))?$
這會變得很長,有很多選擇。如有必要,可以動態生成這樣的正則運算式。
def match_sequence_without_repeats(options, seperator):
def prevent_previous(n):
if n == 0:
return ""
groups = "".join(rf"\{i}" for i in range(1, n 1))
return f"(?!{groups})"
return "".join(
f"(?:{seperator}{prevent_previous(i)}([{options}]))?"
for i in range(len(options))
)
print(f"foo{match_sequence_without_repeats('abc', ' ')}$")
uj5u.com熱心網友回復:
這是 anubhava 答案的修改版本,使用反向參考(在 Python 中有效,至少對我來說更容易理解)而不是正向參考。
[abc]在捕獲組內匹配 using ,然后檢查捕獲組匹配的文本在它之后的任何地方都不會再次出現:
^foo(?:( [abc])(?!.*\1)) $
正則運算式演示
^: 開始foo: 比賽foo(?:: 啟動非捕獲組(?:( [abc])(?!.*\1))( [abc]): 捕獲第 1 組,匹配一個空格后跟a,b, 或c(?!.*\1): 負前瞻,如果第一個捕獲組匹配的文本出現在零個或多個匹配的字符之后,則匹配失敗.
): 結束非捕獲組并匹配1次或多次$: 結尾
uj5u.com熱心網友回復:
我假設字串的元素可以按任意順序出現并出現任意次數。例如,'a foo'應該匹配和'a foo b foo'不應該匹配。
你可以通過一系列使用前瞻的交替來做到這一點,每個感興趣的子串一個,但是當有很多字串需要考慮時,它就變成了狗的早餐。假設您想匹配零或一"foo"和/或零或一"a"。您可以使用以下正則運算式:
^(?:(?!.*\bfoo\b)|(?=(?:(?!\bfoo\b).)*\bfoo\b(?!(.*\bfoo\b))))(?:(?!.*\ba\b)|(?=(?:(?!\ba\b).)*\ba\b(?!(.*\ba\b))))
啟動你的引擎!
例如,這匹配'foofoo'、'aa'和afooa。如果它們不匹配,請洗掉分詞符 ( \b)。
請注意,此運算式首先斷言字串 ( ^) 的開頭,然后是兩個正向前瞻,一個 for'foo'和一個 for 'a'。還要檢查,比如說,'c'一個人會堅持
(?:(?!.*\bc\b)|(?=(?:(?!\bc\b).)*\bc\b(?!(.*\bc\b))))
這與
(?:(?!.*\ba\b)|(?=(?:(?!\ba\b).)*\ba\b(?!(.*\ba\b))))
與\ba\b改變\bc\b。
能夠使用反向參考會很好,但我不知道如何做到這一點。
通過將滑鼠懸停在鏈接中的正則運算式上,可以為運算式的每個元素提供說明。(如果這不清楚,我指的是游標。)
注意
(?!\bfoo\b).
匹配不以單詞開頭的字符'foo'。所以
(?:(?!\bfoo\b).)*
匹配不包含'foo'且不以后'f'跟'oo'.
我會在實踐中提倡這種方法,而不是使用簡單的字串方法嗎?讓我考慮一下。
uj5u.com熱心網友回復:
如果字串的順序無關緊要,并且您想確保每個字串只出現一次,則可以在 Python 中將串列轉換為集合:
my_lst = ['a', 'a', 'b', 'c']
my_set = set(lst)
print(my_set)
# {'a', 'c', 'b'}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/316260.html
下一篇:PerlOOP看不到新方法
