Python正则表达式 - 识别列表中的第一个和最后一个元素。

8
我需要将一些文本文件转换成HTML代码。 我卡在将列表转换为HTML无序列表上。 示例源代码:
``` 一些文本 * 项目1 * 项目2 * 项目3 一些其他的文本 ```
输出应该是:
some text in the document
<ul>
    <li>item 1</li>
    <li>item 2</li>
    <li>item 3</li>
</ul>
some other text

目前,我有这个:

r = re.compile(r'\*(.*)\n')
r.sub('<li>\1</li>', the_text_document)

如何创建一个没有 < ul > 标签的 HTML 列表?
我该如何识别第一个和最后一个项目,并用 < ul > 标签将它们包围起来?


4
只需逐行迭代文档并检查正则表达式。每当成功匹配时,开始一个新的<ul>,每当停止匹配时,插入</ul>。 - Guy Adini
2
谢谢你的回答。由于我在文档中执行了一系列不同的正则表达式替换,所以我更喜欢在这种情况下使用正则表达式。但是,如果我找不到一个合适的正则表达式,这可能是解决方案。 - user1102018
3
为什么不使用 DOM 解析器来处理这个? - Sebastian Hoffmann
1
@Paranaix 因为重新发明轮子非常有趣。 - Loïc Faure-Lacroix
3个回答

1

您可以逐行处理数据...下面这个快速而简单的解决方案可能需要整理一下,但对于您的数据来说,它能够胜任。

with open('data.txt') as inf:
    star_count = 0
    for line in inf:
        line = line.strip()

        if not line.startswith('*'):
            if star_count == 1:
                print'</ul>'
            print line
        else:
            if star_count == 0:
                print '<ul>'
                star_count = 1
            print '  <li>%s</li>'  %line.split('*')[1].strip()

产生:
some text in the document
<ul>
  <li>item 1</li>
  <li>item 2</li>
  <li>item 3</li>
</ul>
some other text

根据您的数据复杂程度,或者如果您有重复的未编号列表等,这将需要修改,您可能需要寻找更通用的解决方案,或修改此起始代码以满足您的需求,只有您可以决定。

更新:

编辑了<li> .. </li>打印行,以消除先前留下的*


谢谢。实际上文档中可能会有许多列表。正如我回答@Guy Adini时所说,除非我找到一个正则表达式来完成任务,否则我可能会使用这个解决方案。 - user1102018
@user1102018 不用谢。我还刚刚更新了我的答案,修改了之前无意中留下的打印行,该行会在生成的项目列表中保留“*”符号。 - Levon

1

或者使用BeautifulSoup

http://www.crummy.com/software/BeautifulSoup/bs4/doc/

编辑

显然我需要给你一些关于如何阅读文档的提示。

  • 打开链接
  • 左侧有一个大菜单(青色)
  • 如果你仔细看,你会发现文档被分成多个部分
    • 杂项
    • 树形导航
    • 搜索树
    • 修改树(搞定了)
    • 输出(搞定了!)

还有很多其他的东西

Beautiful Soup是一个用于从HTML和XML文件中提取数据的Python库。它与您喜欢的解析器一起工作,提供了通俗易懂的方式来浏览、搜索和修改解析树。 它通常可以为程序员节省数小时或数天的工作时间

不要在第一句话后停止阅读...最后一句话和中间的内容也非常重要。

换句话说,你可以创建一个空文档...比如说:

soup = BeautifulSoup("<div></div>")
document = soup.div

然后您阅读文本的每一行..并且每当您有文本时都这样做。

document.append(line)

如果该行以 `*` 开头

ul = document.new_tag('ul')
document.append(ul)
document = ul

然后将文档中的所有li推送...一旦您读到*,只需弹出父级,使文档返回到

。并且不断重复这个过程...您甚至可以递归地执行此操作,将ul插入到ul中。

一旦解析完所有内容...您就可以进行操作了。

str(document)

或者

document.prettify()

编辑

刚刚意识到您并不是在编辑HTML,而是未格式化的文本。您可以尝试使用Markdown。

http://daringfireball.net/projects/markdown/


2
BeautifulSoup可以从HTML中解析文本,问题是如何将文本格式化为HTML。除非BeautifulSoup有我不知道的某些特性? - Francis Yaconiello
2
该页面说:“Beautiful Soup是一个用于从HTML和XML文件中提取数据的Python库”。只要它不会做相反的事情(从非树形结构文档中提取数据),它如何帮助我呢?另外,如果可能的话,我宁愿避免使用另一个库来完成这个任务。 - user1102018
我不确定你所说的“deceived”的意思是什么?我认为你可能在使用一个糟糕的翻译器/翻译。 - Francis Yaconiello
BeautifulSoup是一个DOM操作器。你可以用它来构建你的DOM,并使用它来解析文本。例如,在每个新行上,他会将文本添加到文档中...如果他遇到*,他会添加一个ul,然后添加li,直到他遇到不以*开头的新行,并使用DOM弹出ul...等等。 - Loïc Faure-Lacroix
2
同时,您不希望使用正则表达式来解决此问题:https://dev59.com/X3I-5IYBdhLWcg3wq6do - Mikko Ohtamaa

1

在考虑了一些想法后,我决定使用第二个正则表达式。因此,基本上,在运行第一个正则表达式(来自我的原始帖子,创建<li>标签)之后,我运行:

r = re.compile(r'(<li>.*?</li>\n(?!\s*<li>))', re.DOTALL)
r.sub('<ul>\\1</ul>', string_with_li_tags)

这会查找第一个匹配的<li>标记和最后一个匹配的</li>\n组合,后面不跟随一个<li>标记(这基本上表示整个列表),并添加<ul>标记。

编辑: 我稍微修改了正则表达式,使其不贪婪。这样可以处理同一文档中的多个列表。唯一的要求是列表项之间没有空格,如@Aprillion下面所提到的

编辑2: 修改了负向先行断言,以处理列表项之间的空格,以便涵盖所有情况。


1
它之所以有效,是因为.*是贪婪的,它匹配整个文档,然后回溯1个字符,直到匹配</li>\n为止。否则,负向先行断言将适用于列表项之间带有空格的任何</li>\n <li>,因此在您的正则表达式中没有好处。 - Aprillion
@deathApril,我也尝试了在列表项之间加入空格,如下所示:__"一些文本\n <li>项目1</li>\n <li>项目2</li>\n <li>项目3</li>\n更多的文本"__,同样可行(虽然显示效果不佳,但是每个</li>\n后面有空格)。 - user1102018
这个正则表达式的 JavaScript 等价物是什么? - aradalvand

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接