python
  • regex
  • string
  • 2015-12-23 57 views 4 likes 
    4

    我想用這個詞「和」除了當字「和」分裂以下字符串是引號如何用字符串拆分字符串,除非字符串在python中用引號括起來?

    string = "section_category_name = 'computer and equipment expense' and date >= 2015-01-01 and date <= 2015-03-31" 
    

    所需的結果

    ["section_category_name = 'computer and equipment expense'","date >= 2015-01-01","date <= 2015-03-31"] 
    

    我似乎無法找到內正確的正則表達式模式,正確地分割字符串,以便「計算機和設備費用」不會被分割。

    這裏是我的嘗試:

    re.split('and',string) 
    

    結果

    [" section_category_name = 'computer "," equipment expense' ",' date >= 2015-01-01 ',' date <= 2015-03-31'] 
    

    正如你所看到的結果已經分裂「計算機和設備費用」進入榜單上不同的項目。

    我也試着從this question如下:

    r = re.compile('(?!)[^[]+?(?= *\[)' 
           '|' 
           '\[.+?\]') 
    r.findall(s) 
    

    結果:

    [] 
    

    我也試着從這個question

    result = re.split(r"and+(?=[^()]*(?:\(|$))", string) 
    

    結果如下:

    [" section_category_name = 'computer ", 
    " equipment expense' ", 
    ' date >= 2015-01-01 ', 
    ' date <= 2015-03-31'] 
    

    難題在於之前關於此主題的問題沒有解決如何通過引號內的單詞分割字符串,因爲它們解決了如何通過特殊字符或空格拆分字符串。

    我能得到期望的結果,如果我修改字符串以下

    string = " section_category_name = (computer and equipment expense) and date >= 2015-01-01 and date <= 2015-03-31" 
    result = re.split(r"and+(?=[^()]*(?:\(|$))", string) 
    

    所需的結果

    [' section_category_name = (computer and equipment expense) ', 
    ' date >= 2015-01-01 ', 
    ' date <= 2015-03-31'] 
    

    不過,我需要的功能沒有撇號內的分裂上「和」代替圓括號

    +0

    我已經嘗試了所有上述解決方案,並試圖改變它們,以便能夠將單詞'和'分開,並且運氣不錯。我將繼續發佈我上面嘗試過的所有內容 – Chris

    +2

    簡寫:正則表達式對於手邊的工作來說是一個糟糕的工具。這是真正構建真正解析器的地方之一。 –

    回答

    0

    您可以使用以下正則表達式與re.findall

    ((?:(?!\band\b)[^'])*(?:'[^'\\]*(?:\\.[^'\\]*)*'(?:(?!\band\b)[^'])*)*)(?:and|$) 
    

    請參閱regex demo

    正則表達式由任一的任何的展開的序列,但是一個'直到第一and(與回火貪婪令牌(?:(?!\band\b)[^'])*)之間幷包括單撇號和任何(支撐轉義實體)(與'[^'\\]*(?:\\.[^'\\]*)*'的 - 這也是未包裝版本([^'\\]|\\.)*)。

    的Python code demo

    import re 
    p = re.compile(r'((?:(?!\band\b)[^\'])*(?:\'[^\'\\]*(?:\\.[^\'\\]*)*\'(?:(?!\band\b)[^\'])*)*)(?:and|$)') 
    s = "section_category_name = 'computer and equipment expense' and date >= 2015-01-01 and date <= 2015-03-31" 
    print([x for x in p.findall(s) if x]) 
    
    0

    如果您的所有字符串遵循相同的模式,你可以使用正則表達式來搜索分成3個組。第一組從開始到最後'。然後下一個組是第一個和最後一個「和」之間的所有內容。最後一組是文本的其餘部分。

    import re 
    
    string = "section_category_name = 'computer and equipment expense' and date >= 2015-01-01 and date <= 2015-03-31" 
    
    output = re.match(r"(^.+['].+['])\sand\s(.+)\sand\s(.+)", string).groups() 
    print(output) 
    

    每個組都在正則表達式的括號內定義。方括號定義了一個匹配的特定字符。只有「section_category_name」等於單引號內的內容時,此示例纔會起作用。

    section_category_name = 'something here' and ... 
    
    0

    下面的代碼將工作,並不需要瘋狂的正則表達式來實現它。

    import re 
    
    # We create a "lexer" using regex. This will match strings surrounded by single quotes, 
    # words without any whitespace in them, and the end of the string. We then use finditer() 
    # to grab all non-overlapping tokens. 
    lexer = re.compile(r"'[^']*'|[^ ]+|$") 
    
    string = "section_category_name = 'computer and equipment expense' and date >= 2015-01-01 and date <= 2015-03-31" 
    
    results = [] 
    buff = [] 
    
    # Iterate through all the tokens our lexer identified and parse accordingly 
    for match in lexer.finditer(string): 
        token = match.group(0) # group 0 is the entire matching string 
    
        if token in ('and', ''): 
         # Once we reach 'and' or the end of the string '' (matched by $) 
         # We join all previous tokens with a space and add to our results. 
         results.append(' '.join(buff)) 
         buff = [] # Reset for the next set of tokens 
        else: 
         buff.append(token) 
    
    print results 
    

    Demo

    編輯:這裏有一個更簡潔的版本,與itertools.groupby有效替代for循環的上述聲明。

    import re 
    from itertools import groupby 
    
    string = "section_category_name = 'computer and equipment expense' and date >= 2015-01-01 and date <= 2015-03-31" 
    
    lexer = re.compile(r"'[^']*'|[^\s']+") 
    grouping = groupby(lexer.findall(string), lambda x: x == 'and') 
    results = [ ' '.join(g) for k, g in grouping if not k ] 
    
    print results 
    

    Demo

    0

    我只想使用re.split具有此功能的事實:

    如果捕獲括號中的圖案被使用,然後在圖案中的所有組的文本也返回作爲結果列表的一部分。

    結合使用兩個捕獲組將返回一個None分隔字符串的列表。 這使得正則表達式很簡單,儘管需要一些後合併。

    >>> tokens = re.split(r"('[^']*')|and", string) 
    # ['section_category_name = ', "'computer and equipment expense'", ' ', None, ' date >= 2015-01-01 ', None, ' date <= 2015-03-31']  
    >>> ''.join([t if t else '\0' for t in tokens]).split('\0') 
    ["section_category_name = 'computer and equipment expense' ", ' date >= 2015-01-01 ', ' date <= 2015-03-31'] 
    

    注意,0x00焦炭使用那裏作爲臨時隔膜,所以如果你需要處理與空字符串就不能很好地工作。

    1

    可以使用re.findall生成一個2元組列表,其中第一個元素是帶引號的字符串或空,或者第二個元素是除空格字符或空白以外的任何元素。

    然後可以使用itertools.groupby由單詞「和」(在不帶引號的字符串),然後從列表-COMP裏面的填充元件,例如歸隊分區:

    import re 
    from itertools import groupby 
    
    text = "section_category_name = 'computer and equipment expense'  and date >= 2015-01-01 and date <= 2015-03-31 and blah = 'ooops'" 
    items = [ 
        ' '.join(el[0] or el[1] for el in g) 
        for k, g in groupby(re.findall("('.*?')|(\S+)", text), lambda L: L[1] == 'and') 
        if not k 
    ] 
    

    爲您提供:

    ["section_category_name = 'computer and equipment expense'", 
    'date >= 2015-01-01', 
    'date <= 2015-03-31', 
    "blah = 'ooops'"] 
    

    注意空格也歸了引號的字符串之外 - 不管是可取與否,但...

    還要注意 - 這也讓有點的靈活性,所以你可以將lambda L: L[1] == 'and'更改爲lambda L: L[1] in ('and', 'or'),以便根據不同的詞進行分組,如果需要等等。

    0

    我不確定你想要對圍繞and的空白做什麼,以及你想要對字符串中重複的and做什麼。如果你的字符串是'hello and and bye''hello andand bye',你想要什麼?

    我沒有測試所有的角落案件,我剝周圍的空白「和」,這可能是也可能不是你想要什麼:

    string = "section_category_name = 'computer and equipment expense' and date >= 2015-01-01 and date <= 2015-03-31" 
    res = [] 
    spl = 'and' 
    for idx, sub in enumerate(string.split("'")): 
        if idx % 2 == 0: 
        subsub = sub.split(spl) 
        for jdx in range(1, len(subsub) - 1): 
         subsub[jdx] = subsub[jdx].strip() 
        if len(subsub) > 1: 
         subsub[0] = subsub[0].rstrip() 
         subsub[-1] = subsub[-1].lstrip() 
        res += [i for i in subsub if i.strip()] 
        else: 
        quoted_str = "'" + sub + "'" 
        if res: 
         res[-1] += quoted_str 
        else: 
         res.append(quoted_str) 
    

    一個更簡單的解決辦法,如果你知道and將兩側的空間包圍,而且它不會重複,並且不希望刪除多餘的空格:

    string = "section_category_name = 'computer and equipment expense' and date >= 2015-01-01 and date <= 2015-03-31" 
    spl = 'and' 
    res = [] 
    spaced_spl = ' ' + spl + ' ' 
    for idx, sub in enumerate(string.split("'")): 
        if idx % 2 == 0: 
        res += [i for i in sub.split(spaced_spl) if i.strip()] 
        else: 
        quoted_str = "'" + sub + "'" 
        if res: 
         res[-1] += quoted_str 
        else: 
         res.append(quoted_str) 
    

    輸出:

    ["section_category_name = 'computer and equipment expense'", 'date >= 2015-01-01', 'date <= 2015-03-31'] 
    
    相關問題