如何根据缩进解析代码块

2 投票
2 回答
3303 浏览
提问于 2025-04-17 17:42

我正在写一个工具,用来把类似Markdown的标记语言转换成HTML。我已经完成了大部分代码,除了有序和无序列表的转换部分。我想根据空格的数量来格式化列表(也就是所谓的“缩进规则”)。有效的输入示例如下:

:: List item 
   top level
 :: List item level 2
 :: List item level 2
    :: List item level 3
      :: List item level 4
 :: List item level 2

:: List item top level

::表示一个列表项。缩进的层级可以是任意的。制表符不算在内。我在纸上写了一些解决方案,但我还是没找到实现的方法。我该怎么做呢?

补充说明:只要空格超过一个,任何数量的空格就表示一个新的层级,就像在Python中那样。

我用Python来实现这个工具,但我不想要代码。我想要的是如何去做的解释。而且我希望自己能完整实现,不依赖任何库。我打算把这个标记语言用在我的Jekyll博客上,但这对我来说不仅仅是一个小工具,我想通过这个项目尽可能多地学习正则表达式和解析的知识。提前谢谢你们。

2 个回答

0

这不是一个答案,但我需要块格式。

这个列表应该解析成什么级别呢?

:: List item level 
  :: List item level ?
 :: List item level ?
    :: List item level ?
 :: List item level ?
   :: List item level ?

我觉得你在处理一些在列表中没有意义的特殊情况,其实你应该告诉用户写一些更合理的内容。

3

@delnan 提到的 Python 参考文档 提供了一种不错的方法,但正如文档所说,Python 允许的缩进方式虽然是正确的,但有时候会让人看得很困惑。而且如果你试图充分利用这种灵活性,可能会在调试时遇到麻烦。

为了你的应用,如果你要求每种不同数量的缩进空格表示不同的列表层级,可能会让用户更容易理解。用 Python 3,你可以在不超过四行的代码中找到列表的层级。虽然你不想看到代码解决方案(不过如果你想要,我很乐意分享),但我的大致思路是这样的:

  1. 计算列表中每行开头的空格数量(这不需要使用正则表达式)。
  2. 创建一个集合并对其进行排序,以列出每个层级使用的缩进空格数量,从少到多排列。
  3. 创建一个字典,将每种情况下使用的缩进空格数量与列表层级关联起来。
  4. 使用列表中每行开头的空格数量来查找这个字典,从而得到每行的列表层级。

(已编辑以包含代码并处理多行列表项)

给定:

:: List item
   (this is the second line of the first list item)
 :: List item level 2
 :: List item level 2
    :: List item level 3
      :: List item level 4
 :: List item level 2
:: List item top leve

... 下面的函数生成了这个列表:

:: List item (this is the second line of the first list item)
 :: List item level 2
 :: List item level 2
  :: List item level 3
   :: List item level 4
 :: List item level 2
:: List item top level

... 我认为这是这个测试案例的预期结果。

以下是代码,设计为从标准输入接收列表:

import sys

def findIndent (lst):
    # given a list of text strings, returns a list containing the
    # indentation levels for each string
    spcCount = [len(s)-len(s.lstrip(' ')) for s in lst]
    indent = sorted(set(spcCount))
    levelRef = {indent[i]:i for i in range(len(indent))}
    return [levelRef[i]+1 for i in spcCount]

lst = []
for li in sys.stdin:
    if li.lstrip(' ').find('::') == 0:
        lst.append(li.rstrip())
    else:
        lst[-1] = lst[-1].rstrip() + ' ' + li.lstrip(' ').rstrip()

for i,li in zip(findIndent(lst),lst):
    print (' '*i + li.lstrip())

撰写回答