在Python中解析半结构化文本字符串

2024-06-02 04:59:53 发布

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

我正在尝试解析伪英语脚本,并希望将其转换为另一种机器可读的语言。 然而剧本在过去被许多人写过,而且每个人都有自己的风格。在

例如:

  1. 在设备1上,将字45和46设置为hex 331
  2. 在设备1上,设置字45和46位3..7到280
  3. 在设备1上,将单词45设置为oct 332
  4. 在设备1上,将速度设置为60kts单词3-4到hex 34 (源文本中使用了更多不同的方法)

这个问题并不总是合乎逻辑,也不总是一致的

我查看了Regexp,并匹配了某些单词。这行得通,但当我需要知道下一个单词时(例如在'word24'中,我会匹配'word',然后试着找出下一个标记是不是数字)。在“单词”的情况下,我需要查找要设置的单词以及它们的值。在

在示例1中,它应该生成Set word 45 to hex 331和{} 或者如果可能Set word 45 to hex 331 and word 46 to hex 331

我尝试在re上使用findall方法,它只会给我匹配的单词,然后我必须手动找出下一个单词(即value)

或者,我可以使用一个空格分割字符串并手动处理每个单词,然后可以执行以下操作

假设列表是

['On', 'device1:', 'set', 'Word', '1', '', 'to', '88', 'and', 'word', '2', 'to', '2151']

for i in range (0,sp.__len__()):
    rew = re.search("[Ww]ord", sp[i])
    if rew:
        print ("Found word, next val is ", sp[i+1])

有没有更好的方法来做我想做的事?我研究了一点符号化,但不确定这是否有效,因为语言一开始不是结构化的。在


Tags: andto方法re脚本机器语言手动
2条回答

我建议你开发一个程序,逐步探索人们用来编写脚本的语法。在

举例来说,你的例子中的每一条指令似乎都分为一个设备部分和一个设置部分。所以您可以尝试根据regex ^(.+) set (.+)匹配每一行。如果你发现线条与图案不符,就把它们打印出来。检查输出,找到与其中一些匹配的通用模式,向程序添加相应的正则表达式(或修改现有的正则表达式),然后重复。继续进行,直到您(以非常一般的方式)识别出输入中的每一行。在

(由于大小写似乎不一致,您可以进行不区分大小写的匹配,或者在开始处理之前将每行转换为小写。更一般地说,您可以找到其他简化后续处理的“规范化”。E、 g.如果人们对空格不一致,你可以把每次空格字符转换成一个空格。)

(如果您的输入有印刷错误,例如有人为“set”写了“ste”,那么您可以更改regex以允许这种情况(... (set|ste) ...),或者转到输入文件(的副本)并修复该打字错误。)

然后返回匹配^(.+) set (.+)的行,为每个行打印出第一组,并对这些子字符串重复上述过程。 然后在每个“set”指令中对第二组重复该过程。等等,递归地。在

最终,您的程序将成为脚本语言的解析器。此时,您可以开始添加代码,将每个可识别的构造转换为输出语言。在

根据您使用Python的经验,您可以找到使代码简洁的方法。在

根据您实际想要从这些字符串中获得什么,您可以使用解析器,例如parsimonious

from parsimonious.nodes import NodeVisitor
from parsimonious.grammar import Grammar

grammar = Grammar(
    r"""
    command     = set operand to? number (operator number)* middle? to? numsys? number
    operand     = (~r"words?" / "speed") ws
    middle      = (~r"[Ww]ords" / "bits")+ ws number
    to          = ws "to" ws
    number      = ws ~r"[-\d.]+" "kts"? ws
    numsys      = ws ("oct" / "hex") ws
    operator    = ws "and" ws
    set         = ~"[Ss]et" ws
    ws          = ~r"\s*"
    """
)

class HorribleStuff(NodeVisitor):
    def __init__(self):
        self.cmds = []

    def generic_visit(self, node, visited_children):
        pass

    def visit_operand(self, node, visited_children):
        self.cmds.append(('operand', node.text))

    def visit_number(self, node, visited_children):
        self.cmds.append(('number', node.text))


examples = ['Set word 45 and 46 to hex 331',
            'set words 45 and 46 bits 3..7 to 280',
            'set word 45 to oct 332',
            'set speed to 60kts Words 3-4 to hex 34']


for example in examples:
    tree = grammar.parse(example)
    hs = HorribleStuff()
    hs.visit(tree)
    print(hs.cmds)

这会导致

^{pr2}$

相关问题 更多 >