【问题标题】:Regular Expression to match all non alphanumeric characters except "<--"正则表达式匹配除“<--”之外的所有非字母数字字符
【发布时间】:2020-01-15 15:06:03
【问题描述】:

我正在尝试在 python 中创建一种玩具语言,但我在创建我的词法分析器时遇到了困难。用我的语言分配变量的方法是使用箭头(“

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

    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"']

【问题讨论】:

  • [item for item in self.source_code.split() if item]?
  • "foobar &lt;-- 2.3+4.42" 应该分成什么?我猜["foobar", "&lt;--", "2.3", "+", "4.2"]?在这种情况下,普通的.split() 可能不会这样做......
  • @Kevin 说得对
  • 您可能需要单独处理表达式。也许按照上面的方法得到 3 个部分并用answers here 之类的东西处理表达式
  • 你将如何消除i&lt;--j 的歧义?假设您允许预先递减,这可能意味着 i := jj := j-1; i &lt; j

标签: python regex split match


【解决方案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|&lt;--) 正在寻找选择,它们是:

  1. \b\d+(?:\.\d*)?\b 匹配单词边界上的 123、123.、123.45
  2. \b\.\d+\b 匹配单词边界上的 .45
  3. \b\w+\b 在单词边界上匹配 Hi
  4. &lt;-- 匹配
  5. `\s+' 匹配连续的空格
  6. \W+ 匹配上面未匹配的所有其他内容(其他运算符)

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

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

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 )

【讨论】:

    【解决方案2】:

    通过稍微修改优雅 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 != ' ')]
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-03-22
      • 1970-01-01
      • 2016-04-03
      • 1970-01-01
      • 2019-02-15
      • 1970-01-01
      • 1970-01-01
      • 2013-05-01
      相关资源
      最近更新 更多