簡體   English   中英

重復序列的正則表達式

[英]Regular expression for repeating sequence

我想匹配由逗號分隔的三個字符的字母序列(只允許使用字母'a'、'b'、'c')(最后一組不以逗號結尾)。

例子:

abc,bca,cbb
ccc,abc,aab,baa
bcb

我寫了以下正則表達式:

re.match('([abc][abc][abc],)+', "abc,defx,df")

但是它不能正常工作,因為對於上面的例子:

>>> print bool(re.match('([abc][abc][abc],)+', "abc,defx,df")) # defx in second group
True
>>> print bool(re.match('([abc][abc][abc],)+', "axc,defx,df")) # 'x' in first group
False

它似乎只檢查第一組三個字母,但它忽略了其余的。 如何正確編寫這個正則表達式?

嘗試以下正則表達式:

^[abc]{3}(,[abc]{3})*$

^...$從字符串的開頭到結尾
[...]給定字符之一
...{3}三遍之前的短語
(...)* 0 到 n 次括號中的字符

你要求它用你的正則表達式找到的是“至少三個字母 a、b、c”——這就是“+”給你的。 之后發生的任何事情對正則表達式都無關緊要。 您可能希望包含“$”,意思是“行尾”,以確保該行必須全部由允許的三元組組成。 但是,在當前形式中,您的正則表達式還要求最后一個三元組以逗號結尾,因此您應該明確編碼並非如此。 嘗試這個:

re.match('([abc][abc][abc],)*([abc][abc][abc])$'

這將找到任意數量的允許三元組,后跟逗號(可能為零),然后是不帶逗號的三元組,然后是行尾。

編輯:不需要包含“^”(字符串開頭)符號,因為match方法已經僅在字符串的開頭檢查匹配項。

強制性的“您不需要正則表達式”解決方案:

all(letter in 'abc,' for letter in data) and all(len(item) == 3 for item in data.split(','))

您需要遍歷找到的值序列。

data_string = "abc,bca,df"

imatch = re.finditer(r'(?P<value>[abc]{3})(,|$)', data_string)

for match in imatch:
    print match.group('value')

所以檢查字符串是否匹配模式的正則表達式將是

data_string = "abc,bca,df"

match = re.match(r'^([abc]{3}(,|$))+', data_string)

if match:
    print "data string is correct"

你的結果並不奇怪,因為正則表達式

([abc][abc][abc],)+

嘗試匹配包含三個字符[abc]后跟逗號一次或多次的字符串中任意位置的字符串。 所以最重要的部分是確保字符串中沒有更多內容 - 正如 scessor 建議的那樣,在正則表達式中添加^ (字符串開頭)和$ (字符串結尾)。

要僅重復一系列模式,您需要使用非捕獲組,類似(?:...)的構造,並在右括號后立即應用量詞。 左括號后的問號和冒號是創建非捕獲組(SO post)的語法。

例如:

  • (?:abc)+匹配abcabcabcabcabcabc等字符串。
  • (?:\d+\.){3}匹配像1.12.2. , 000.00000.0. , ETC。

在這里,您可以使用

^[abc]{3}(?:,[abc]{3})*$
          ^^

請注意,在許多 Python 正則表達式方法中,使用捕獲組充滿了不受歡迎的效果。 請參閱re.findall中描述的一個經典問題表現怪異,例如,如果模式中存在捕獲組,則re.findall和所有其他在幕后使用此函數的正則表達式方法僅返回捕獲的子字符串。

在 Pandas 中,當您只需要對模式序列進行分組時,使用非捕獲組也很重要: Series.str.contains抱怨this pattern has match groups. To actually get the groups, use str.extract. this pattern has match groups. To actually get the groups, use str.extract. Series.str.extractSeries.str.extractallSeries.str.findall將表現為re.findall

不使用正則表達式的替代方法(盡管是蠻力方式):

>>> def matcher(x):
        total = ["".join(p) for p in itertools.product(('a','b','c'),repeat=3)]
            for i in x.split(','):
                if i not in total:
                    return False
         return True

>>> matcher("abc,bca,aaa")
    True
>>> matcher("abc,bca,xyz")
    False
>>> matcher("abc,aaa,bb")
    False

如果您的目標是驗證一個字符串是否由三個字母 a、b 和 c 組成:

for ss in ("abc,bbc,abb,baa,bbb",
           "acc",
           "abc,bbc,abb,bXa,bbb",
           "abc,bbc,ab,baa,bbb"):
    print ss,'   ',bool(re.match('([abc]{3},?)+\Z',ss))

結果

abc,bbc,abb,baa,bbb     True
acc     True
abc,bbc,abb,bXa,bbb     False
abc,bbc,ab,baa,bbb     False

\Z表示:字符串的結尾。 它的存在迫使匹配直到字符串的最后

順便說一句,我也喜歡 Sonya 的形式,在某種程度上它更清晰:

bool(re.match('([abc]{3},)*[abc]{3}\Z',ss))

暫無
暫無

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

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