2013-04-18 39 views
6

Tôi có các chuỗi như "aaaaabbbbbbbbbbbbbbccccccccccc". Số lượng ký tự có thể khác nhau và đôi khi có thể có dấu gạch ngang bên trong chuỗi, như "aaaaa-bbbbbbbbbbbbbbccccccccccc".Chuỗi phân tách Python theo mẫu

Có cách nào thông minh để chia tách nó "aaaaa", "bbbbbbbbbbbbbb", "ccccccccccc" và nhận chỉ mục của nó được chia nhỏ hoặc chỉ nhận các chỉ mục mà không lặp qua tất cả các chuỗi không? Nếu dấu gạch ngang nằm giữa các mẫu, nó có thể kết thúc ở bên trái hoặc bên phải, nó sẽ luôn được xử lý giống nhau.

Bất kỳ ý tưởng nào?

Trả lời

11

Biểu thức chính quy MatchObject kết quả bao gồm các chỉ số của trận đấu. Những gì còn lại là để phù hợp với nhân vật lặp đi lặp lại:

import re 

repeat = re.compile(r'(?P<start>[a-z])(?P=start)+-?') 

sẽ chỉ phù hợp nếu một nhân vật thư nhất định (a - z) được lặp lại ít nhất một lần:

>>> for match in repeat.finditer("aaaaabbbbbbbbbbbbbbccccccccccc"): 
...  print match.group(), match.start(), match.end() 
... 
aaaaa 0 5 
bbbbbbbbbbbbbb 5 19 
ccccccccccc 19 30 

Các .start().end() phương pháp trên kết quả trận đấu cung cấp cho bạn vị trí chính xác trong chuỗi đầu vào.

Dấu gạch ngang có trong các trận đấu, nhưng không phải không lặp lại ký tự:

>>> for match in repeat.finditer("a-bb-cccccccc"): 
...  print match.group(), match.start(), match.end() 
... 
bb- 2 5 
cccccccc 5 13 

Nếu bạn muốn phần a- là một trận đấu, bạn chỉ cần thay thế các + với một số nhân *:

repeat = re.compile(r'(?P<start>[a-z])(?P=start)*-?') 
+0

Làm thế nào tôi có thể giữ các dấu gạch ngang? Ví dụ: "aaaaa -", "bbbbbbbbbbbbbb", "ccccccccccc". – Trollbrot

+0

@ Fitz: Xin lỗi, tôi nghĩ bạn không muốn chúng. Ngày đọc lại, tôi thấy rằng bạn làm. Tôi bao gồm chúng với các chữ cái trước. –

+0

Tuyệt vời! Cảm ơn rất nhiều. Tôi đoán tôi nên thực sự nhìn sâu hơn vào các biểu thức thông thường. – Trollbrot

3

Còn việc sử dụng itertools.groupby thì sao?

>>> s = 'aaaaabbbbbbbbbbbbbbccccccccccc' 
>>> from itertools import groupby 
>>> [''.join(v) for k,v in groupby(s)] 
['aaaaa', 'bbbbbbbbbbbbbb', 'ccccccccccc'] 

Điều này sẽ đặt - làm chất nền của riêng chúng mà có thể dễ dàng lọc ra.

>>> s = 'aaaaa-bbbbbbbbbbbbbb-ccccccccccc' 
>>> [''.join(v) for k,v in groupby(s) if k != '-'] 
['aaaaa', 'bbbbbbbbbbbbbb', 'ccccccccccc'] 
+0

Bạn có thể nghĩ ra một cách hay để có được các chỉ mục không? Điều tốt nhất tôi có thể nghĩ ra là 'grouped = [(k, list (g)) cho k, g trong groupby (liệt kê (s), key = lambda x: x [1])]; [(k, g [0] [0], g [-1] [0]) cho k, g theo nhóm] '. Trong python 3 tôi đoán bạn có thể sử dụng 'tích lũy' trên độ dài quá. – DSM

+0

@DSM - Đúng vậy. Tôi bị mất một phần về các chỉ số ... Không chắc chắn về một cách tốt để làm sạch điều đó ... – mgilson

0
str="aaaaabbbbbbbbbbbbbbccccccccccc" 
p = [0] 
for i, c in enumerate(zip(str, str[1:])): 
    if c[0] != c[1]: 
     p.append(i + 1) 
print p 

# [0, 5, 19] 
Các vấn đề liên quan