正则表达式匹配除“ <-”以外的所有非字母数字字符

时间:2019-09-13 18:29:47

标签: python regex split match

我正在尝试用python创建一种玩具语言,但是在创建词法分析器时遇到了困难。用我的语言分配变量的方法是使用箭头(“ <-”),因此我想为此创建令牌。我还希望能够写浮点数(3.2、1.0等)。

以下是当前我如何拆分语言的源代码,但这会拆分到每个非字母数字字符上。

    word_list = re.split('(\W)', self.source_code)
    word_list = [elem for elem in word_list if (elem != '' and elem != ' ')]

例如:

Hi <-- 1.2

转到:

['Hi', '<', '-', '-', '1', '.', '2', '\n']

但我希望将其拆分为

['Hi', '<--', '1.2']

我想知道是否可以对每个字母数字字符进行拆分,除非存在“ <-”或浮点数,而当仍拆分为“ <”,“-”,“。”时。是一个人。

编辑

一个更复杂的示例:

DECLARE Number: INTEGER
DECLARE Hi: REAL
Hi <-- 1.2
INPUT Number

IF Number + Hi > 3
    THEN
        OUTPUT "Hello"

应该去

['DECLARE', 'Number', ':', 'INTEGER','\n' 'DECLARE', 'Hi', ':', 'REAL','\n', 'Hi', '<--', '1.2','\n', 'INPUT', 'Number', '\n', '\n', 'IF', 'Number', '+', 'Hi', '>', '3','\n', '\t', 'THEN', '\n', '\t', '\t', 'OUTPUT', '"Hello"']

2 个答案:

答案 0 :(得分:1)

通常,用于编程语言的词法分析器让您为要解析的语言所拥有的每种令牌类型定义正则表达式。然后,它建立一个有限状态自动机,将输入作为字符串读取,并且这样做,它会在识别各种标记的状态之间进行转换。因此,我采用的方法是尝试定义每个令牌的外观,并尝试在输入中进行匹配。现在,老实说,我并没有花很大的力气就数字和标识符找到最好的正则表达式(我什至不知道您的规则是什么)。我只想表明我相信您应该采取的方法:

s = 'Hi  <--  (1.2)'
word_list = re.findall(r'(\b\d+(?:\.\d*)?\b|\b\.\d+\b|\b\w+\b|<--|\s+|\W+)', s)
print(word_list)

打印:

['Hi', '  ', '<--', '  ', '(', '1.2', ')']

正则表达式'(\b\d+(?:\.\d*)?\b|\b\.\d+\b|\b\w+\b|<--)正在寻找以下选择:

  1. \b\d+(?:\.\d*)? \ b在单词边界上全部匹配123、123。,123.45
  2. \b\.\d+\b在单词边界上匹配.45
  3. \b\w+\b在单词边界上匹配Hi
  4. <--匹配<-(无边界条件-也许这不是您想要的)
  5. `\ s +'匹配连续的空格
  6. \W+匹配上面所有不匹配的内容(其他运算符)

您需要确保所有内容都最终匹配。然后,您可能需要查看已匹配的内容(请参阅上面的项目6),以查看它是否实际上是合法的令牌。

因此,例如,如果<--是唯一有效的运算符,则以下将是一种方法:

import re

s = 'Hi  <--  (1.2)'
for m in re.finditer(r'(?P<OK>\b\d+(?:\.\d*)?\b|\b\.\d+\b|\b\w+\b|<--)|(?P<IGNORE>\s+)|(?P<ERROR>\W+)', s):
    if m.group('ERROR') is not None:
        print('Unrecognized token', m.group('ERROR'))
    elif m.group('OK') is not None:
        print(m.group('OK'))

各种匹配项被标记为OK,IGNORE(空格)或ERROR。上面的照片:

Hi
<--
Unrecognized token (
1.2
Unrecognized token )

答案 1 :(得分:1)

通过稍微修改Elegant Odoo的代码,我设法找到了解决方案。

    split_pattern = '(<--|[\+\-\*\(\)/%:\{\},\[\]<>=(\n)(\t) ]|(?<!\d)[.](?!\d))'
    word_list = re.split(split_pattern, self.source_code)
    word_list = [elem for elem in word_list if (elem != '' and elem != ' ')]