2010-01-25 39 views
123

Đây là cách đơn giản nhất để giải thích điều này. Đây là những gì tôi đang sử dụng:Trong Python, làm cách nào để tách một chuỗi và giữ các dấu tách?

re.split('\W', 'foo/bar spam\neggs') 
-> ['foo', 'bar', 'spam', 'eggs'] 

Dưới đây là những gì tôi muốn:

someMethod('\W', 'foo/bar spam\neggs') 
-> ['foo', '/', 'bar', ' ', 'spam', '\n', 'eggs'] 

Lý do là tôi muốn chia một chuỗi thành tokens, vận dụng nó, sau đó đưa nó trở lại với nhau một lần nữa.

+1

những gì hiện '\ W' là viết tắt của? Tôi thất bại trên google nó. – Ooker

+2

Một ký tự _non-word_ [xem tại đây để biết chi tiết] (https://docs.python.org/2/library/re.html#regular-expression-syntax) – Russell

Trả lời

168
>>> re.split('(\W)', 'foo/bar spam\neggs') 
['foo', '/', 'bar', ' ', 'spam', '\n', 'eggs'] 
+12

Thật tuyệt. Tôi không biết re.split đã làm điều đó với các nhóm chụp. –

+7

@Laurence: Vâng, nó được ghi lại: http://docs.python.org/library/re.html#re.split: "Tách chuỗi bằng các lần xuất hiện của mẫu. Nếu việc ghi dấu ngoặc đơn được sử dụng trong mẫu, thì văn bản của tất cả các nhóm trong mẫu cũng được trả về như một phần của danh sách kết quả. " –

+17

Nó không được ghi nhận nghiêm túc. Tôi đã sử dụng Python trong 14 năm và chỉ tìm thấy điều này. – smci

1

Bạn cũng có thể chia nhỏ một chuỗi với một mảng các chuỗi thay vì một biểu thức chính quy, như thế này:

def tokenizeString(aString, separators): 
    #separators is an array of strings that are being used to split the the string. 
    #sort separators in order of descending length 
    separators.sort(key=len) 
    listToReturn = [] 
    i = 0 
    while i < len(aString): 
     theSeparator = "" 
     for current in separators: 
      if current == aString[i:i+len(current)]: 
       theSeparator = current 
     if theSeparator != "": 
      listToReturn += [theSeparator] 
      i = i + len(theSeparator) 
     else: 
      if listToReturn == []: 
       listToReturn = [""] 
      if(listToReturn[-1] in separators): 
       listToReturn += [""] 
      listToReturn[-1] += aString[i] 
      i += 1 
    return listToReturn 


print(tokenizeString(aString = "\"\"\"hi\"\"\" hello + world += (1*2+3/5) '''hi'''", separators = ["'''", '+=', '+', "/", "*", "\\'", '\\"', "-=", "-", " ", '"""', "(", ")"])) 
2
# This keeps all separators in result 
########################################################################## 
import re 
st="%%(c+dd+e+f-1523)%%7" 
sh=re.compile('[\+\-//\*\<\>\%\(\)]') 

def splitStringFull(sh, st): 
    ls=sh.split(st) 
    lo=[] 
    start=0 
    for l in ls: 
    if not l : continue 
    k=st.find(l) 
    llen=len(l) 
    if k> start: 
     tmp= st[start:k] 
     lo.append(tmp) 
     lo.append(l) 
     start = k + llen 
    else: 
     lo.append(l) 
     start =llen 
    return lo 
    ############################# 

li= splitStringFull(sh , st) 
['%%(', 'c', '+', 'dd', '+', 'e', '+', 'f', '-', '1523', ')%%', '7'] 
7

Một giải pháp không-regex mà hoạt động tốt trên Python 3

# Split strings and keep separator 
test_strings = ['<Hello>', 'Hi', '<Hi> <Planet>', '<', ''] 

def split_and_keep(s, sep): 
    if not s: return [''] # consistent with string.split() 

    # Find replacement character that is not used in string 
    # i.e. just use the highest available character plus one 
    # Note: This fails if ord(max(s)) = 0x10FFFF (ValueError) 
    p=chr(ord(max(s))+1) 

    return s.replace(sep, sep+p).split(p) 

for s in test_strings: 
    print(split_and_keep(s, '<')) 


# If the unicode limit is reached it will fail explicitly 
unicode_max_char = chr(1114111) 
ridiculous_string = '<Hello>'+unicode_max_char+'<World>' 
print(split_and_keep(ridiculous_string, '<')) 
9

Nếu bạn đang chia nhỏ trên dòng mới, hãy sử dụng splitlines(True) .

>>> 'line 1\nline 2\nline without newline'.splitlines(True) 
['line 1\n', 'line 2\n', 'line without newline'] 

(Không phải là một giải pháp chung, nhưng thêm này đây trong trường hợp một người nào đó đi kèm ở đây không nhận ra phương pháp này tồn tại.)

1

Nếu ai muốn chia chuỗi trong khi vẫn giữ dải phân cách bởi regex mà không nhóm chụp:

def finditer_with_separators(regex, s): 
    matches = [] 
    prev_end = 0 
    for match in regex.finditer(s): 
     match_start = match.start() 
     if (prev_end != 0 or match_start > 0) and match_start != prev_end: 
      matches.append(s[prev_end:match.start()]) 
     matches.append(match.group()) 
     prev_end = match.end() 
    if prev_end < len(s): 
     matches.append(s[prev_end:]) 
    return matches 

regex = re.compile(r"[\(\)]") 
matches = finditer_with_separators(regex, s) 

Nếu một giả định rằng regex được gói lên chụp nhóm:

def split_with_separators(regex, s): 
    matches = list(filter(None, regex.split(s))) 
    return matches 

regex = re.compile(r"([\(\)])") 
matches = split_with_separators(regex, s) 

Cả hai cách cũng sẽ loại bỏ các nhóm trống rỗng, vô ích và gây phiền nhiễu trong hầu hết các trường hợp.

1

Nếu bạn chỉ có 1 phân cách, bạn có thể sử dụng danh sách comprehensions:

text = 'foo,bar,baz,qux' 
sep = ',' 

phụ/prepending separator:

result = [x+sep for x in text.split(sep)] 
#['foo,', 'bar,', 'baz,', 'qux,'] 
# to get rid of trailing 
result[-1] = result[-1].strip(sep) 
#['foo,', 'bar,', 'baz,', 'qux'] 

result = [sep+x for x in text.split(sep)] 
#[',foo', ',bar', ',baz', ',qux'] 
# to get rid of trailing 
result[0] = result[0].strip(sep) 
#['foo', ',bar', ',baz', ',qux'] 

Separator vì nó là yếu tố riêng:

result = [u for x in text.split(sep) for u in (x, sep)] 
#['foo', ',', 'bar', ',', 'baz', ',', 'qux', ','] 
results = result[:-1] # to get rid of trailing 
Các vấn đề liên quan