使用多个ifelse和split()简化特定字符串模式的提取

2024-07-05 14:26:49 发布

您现在位置:Python中文网/ 问答频道 /正文

给定这样的字符串:

>>> s = "X/NOUN/dobj>_hold/VERB/ROOT_<membership/NOUN/dobj_<with/ADP/prep_<Y/PROPN/pobj_>,/PUNCT/punct"

首先我想用下划线分割字符串,即:

>>> s.split('_')
['X/NOUN/dobj>',
 'hold/VERB/ROOT',
 '<membership/NOUN/dobj',
 '<with/ADP/prep',
 '<Y/PROPN/pobj',
 '>,/PUNCT/punct']

我们假设下划线仅用作分隔符,并且从不作为要提取的子字符串的一部分存在。你知道吗

然后,我需要首先检查上述拆分列表中的每个“节点”是否以“>;”、“<;”开头或结尾,然后将其移除,并将相应的方括号作为子列表的结尾,例如:

result = []
nodes = s.split('_')
for node in nodes:
    if node.endswith('>'):
        result.append( node[:-1].split('/') + ['>'] )
    elif node.startswith('>'):
        result.append(  node[1:].split('/') + ['>'] )
    elif node.startswith('<'):
        result.append(  node[1:].split('/') + ['<'] )
    elif node.endswith('<'):
        result.append(  node[:-1].split('/') + ['<'] )
    else:
        result.append(  node.split('/') + ['-'] )

如果它不是以尖括号开始,那么我们将-附加到子列表的末尾。你知道吗

[输出]:

[['X', 'NOUN', 'dobj', '>'],
 ['hold', 'VERB', 'ROOT', '-'],
 ['membership', 'NOUN', 'dobj', '<'],
 ['with', 'ADP', 'prep', '<'],
 ['Y', 'PROPN', 'pobj', '<'],
 [',', 'PUNCT', 'punct', '>']]

给定原始输入字符串,是否有一种不那么冗长的方法来获得结果?也许是正则表达式和组?


Tags: 字符串nodewithrootresultmembershipsplitnoun
3条回答

使用此选项:

import re
s_split = "X/NOUN/dobj>_hold/VERB/ROOT_<membership/NOUN/dobj_<with/ADP/prep_<Y/PROPN/pobj_>,/PUNCT/punct".split('_')
for i, text in enumerate(s_split):
    Left, Mid, Right = re.search('^([<>]?)(.*?)([<>]?)$', text).groups()
    s_split[i] = Mid.split('/') + [Left+Right or '-']

print s_split

我找不到一个较短的答案。你知道吗

使用三进制来缩短代码。例如:print None or "a"将打印a。还可以使用regex轻松解析<>的出现。你知道吗

s = 'X/NOUN/dobj>_hold/VERB/ROOT_<membership/NOUN/dobj_<with/ADP/prep_<Y/PROPN/pobj_>,/PUNCT/punct'

def get_sentinal(node):
    if not node:
        return '-'
    # Assuming the node won't contain both '<' and '>' at a same time
    for index in [0, -1]:
        if node[index] in '<>':
            return node[index]
    return '-'

results = [
    node.strip('<>').split('/') + [get_sentinal(node)]
    for node in s.split('_')
]

print(results)

这并没有使它显著地变短,但我个人认为它在某种程度上是更干净一点。你知道吗

是的,虽然不漂亮:

s = "X/NOUN/dobj>_hold/VERB/ROOT_<membership/NOUN/dobj_<with/ADP/prep_<Y/PROPN/pobj_>,/PUNCT/punct"

import re

out = []
for part in s.split('_'):
    Left, Mid, Right = re.search('^([<>]|)(.*?)([<>]|)$', part).groups()
    tail = ['-'] if not Left+Right else [Left+Right]
    out.append(Mid.split('/') + tail)

print(out)

联机试用:https://repl.it/Civg

这主要取决于两件事:

  1. 一种正则表达式模式,它总是组成三个组()()(),其中边缘组只查找字符<>或无([<>]|),中间组匹配所有字符(非贪婪)(.*?)。整个过程锚定在字符串的开始(^)和结束($),因此它使用整个输入字符串。你知道吗
  2. 假设字符串的两端永远不会有角度,那么组合的字符串Left+Right要么是一个空字符串加上要放在末尾的字符,要么是一个表示需要破折号的完全空字符串。你知道吗

相关问题 更多 >