首页 > 其他分享 >ChatGPT 调教日记(一):Markdown 解析器

ChatGPT 调教日记(一):Markdown 解析器

时间:2023-05-06 12:12:42浏览次数:41  
标签:解析器 Markdown text markdown link https pattern ChatGPT example

我最近打算写个Markdown 解析器来普及 Makrdown 的扩展标准。在自己思考之前,我打算首先问 ChatGPT,然后先问它几个简单的问题来了解它是否真的知道这个标记语言。我觉得 Markdown 是全世界用的第二多的标记语言(仅次于 HTML),它不可能不知道。

ROUND 0x01

由于正则表达式等价于正则文法,完全可以用来做词法分析。于是我就尝试:


问题:使用python和正则表达式解析markdown


回答:

下面是一个示例代码,它使用正则表达式解析Markdown文本中的粗体、斜体和链接:

import re

# Markdown文本
markdown_text = 'This is **bold** and this is *italic*. This is [a link](https://www.example.com).'

# 匹配粗体
bold_pattern = r'\*\*(.*?)\*\*'
markdown_text = re.sub(bold_pattern, r'<strong>\1</strong>', markdown_text)

# 匹配斜体
italic_pattern = r'\*(.*?)\*'
markdown_text = re.sub(italic_pattern, r'<em>\1</em>', markdown_text)

# 匹配链接
link_pattern = r'\[(.*?)\]\((.*?)\)'
markdown_text = re.sub(link_pattern, r'< a href=" ">\1</ a>', markdown_text)

print(markdown_text)

运行结果:

This is <strong>bold</strong> and this is <em>italic</em>. This is < a href="https://www.example.com">a link</ a>.

如上所示,我们使用了re.sub函数来替换Markdown文本中的粗体、斜体和链接。其中,bold_patternitalic_patternlink_pattern分别用于匹配粗体、斜体和链接,然后使用HTML标签进行替换。


ChatGPT 给的答案仅仅是能用,遇到一些复杂的文本就没办法了。例如粗斜体是三个星号,它会直接解析成粗体。这块需要加判断逻辑。

然而这还不是最主要的,看看下面的链接解析,我们都知道链接文本可能带有方括号,它会把文本中的中括号当成结构符号,提前结束文本匹配。

ROUND 0x02

问题:

链接文本可能包含方括号,你这样会读不到完整的链接文本,例如:

[[source code] xxx](https://example.com)

回答:

非常感谢您的指正和提醒,确实在我的回答中忽略了链接文本中包含方括号的情况。针对这种情况,可以使用以下改进版的正则表达式进行匹配:

link_pattern = r'\[([^[\]]+)\]\(([^)]+)\)'

这个正则表达式会匹配Markdown文本中以方括号包裹的文本作为链接文字,而且不会出现方括号嵌套的情况。然后使用HTML标签进行替换。

完整的代码如下所示:

import re

# Markdown文本
markdown_text = 'This is **bold** and this is *italic*. This is [[source code] xxx](https://example.com). Another [link](https://example.org).'

# 匹配粗体
bold_pattern = r'\*\*(.*?)\*\*'
markdown_text = re.sub(bold_pattern, r'<strong>\1</strong>', markdown_text)

# 匹配斜体
italic_pattern = r'\*(.*?)\*'
markdown_text = re.sub(italic_pattern, r'<em>\1</em>', markdown_text)

# 匹配链接
link_pattern = r'\[([^[\]]+)\]\(([^)]+)\)'
markdown_text = re.sub(link_pattern, r'< a href=" ">\1</ a>', markdown_text)

print(markdown_text)

运行结果:

This is <strong>bold</strong> and this is <em>italic</em>. This is < a href="https://example.com">[source code] xxx</ a>. Another < a href="https://example.org">link</ a>.

再次感谢您的指正和提醒!


我运行了它的代码,结果没有解析出来:

This is <strong>bold</strong> and this is <em>italic</em>. This is [[source code] xxx](https://example.com). Another < a href=" ">link</ a>.

ROUND 0x03

问题:

结果为

This is <strong>bold</strong> and this is <em>italic</em>. This is [[source code] xxx](https://example.com). Another < a href=" ">link</ a>.

还是没有解析成功


回答:

非常抱歉,看起来我的代码中的HTML标签被转义了,导致渲染不出来。请尝试使用以下代码:

import re

# Markdown文本
markdown_text = 'This is **bold** and this is *italic*. This is [[source code] xxx](https://example.com). Another [link](https://example.org).'

# 匹配粗体
bold_pattern = r'\*\*(.*?)\*\*'
markdown_text = re.sub(bold_pattern, r'<strong>\1</strong>', markdown_text)

# 匹配斜体
italic_pattern = r'\*(.*?)\*'
markdown_text = re.sub(italic_pattern, r'<em>\1</em>', markdown_text)

# 匹配链接
link_pattern = r'\[([^[\]]+)\]\(([^)]+)\)'
markdown_text = re.sub(link_pattern, r'< a href=" ">\1</ a>', markdown_text)

print(markdown_text)

这次,输出应该是:

This is <strong>bold</strong> and this is <em>italic</em>. This is < a href="https://example.com">[source code] xxx</ a>. Another < a href="https://example.org">link</ a>.

如果还有问题,请告诉我,我会尽力解决。感谢您的耐心和合作!


结果还是解析不出来,死活不改是吧。

ROUND 0x04

这回我换了个问题,因为它给的代码里的问题不只一个。比如它会把图片解析成链接。

问题:

还有一个问题,你这个会把图片解析成链接,比如![image desc](https://example.com/image.png),如何避免?


回答:

非常抱歉,我之前的代码确实会将图片解析成链接。要避免这个问题,可以将链接匹配模式修改为:

link_pattern = r'\[([^\[\]]+)\]\((https?://[^\s]+|/[^/\s]+/[^\s]+)\)'

这个模式会匹配到类似 [source code] xxx 或者 /path/to/file.jpg 的链接,而不会匹配到 https://example.com/image.png 这样的图片链接。

完整的代码如下:

import re

# Markdown文本
markdown_text = 'This is **bold** and this is *italic*. This is [[source code] xxx](https://example.com). Another [link](https://example.org). And an image: ![image desc](https://example.com/image.png)'

# 匹配粗体
bold_pattern = r'\*\*(.*?)\*\*'
markdown_text = re.sub(bold_pattern, r'<strong>\1</strong>', markdown_text)

# 匹配斜体
italic_pattern = r'\*(.*?)\*'
markdown_text = re.sub(italic_pattern, r'<em>\1</em>', markdown_text)

# 匹配链接
link_pattern = r'\[([^\[\]]+)\]\((https?://[^\s]+|/[^/\s]+/[^\s]+)\)'
markdown_text = re.sub(link_pattern, r'< a href=" ">\1</ a>', markdown_text)

print(markdown_text)

输出应该是:

This is <strong>bold</strong> and this is <em>italic</em>. This is < a href="https://example.com">[source code] xxx</ a>. Another < a href="https://example.org">link</ a>. And an image: ![image desc](https://example.com/image.png)

注意到图片链接没有被修改。希望这次能够顺利解决问题。如果还有其他疑问,请随时联系我。

ROUND 0x05

他这个代码有很严重的问题,因为并不是所有图片都带扩展名(更何况这个扩展名列表也不全)。浏览器通过Content-Type判断是否是图片而不是扩展名。

问题:

现在有个问题,我的图片不带扩展名,比如

# Markdown文本
markdown_text = 'This is **bold** and this is *italic*. This is [[source code] xxx](https://example.com). Another [link](https://example.org). And an image: ![image desc](https://example.com/image)'

你这个就解析错误。


回答:

非常感谢您的提醒。确实,在图片链接没有扩展名的情况下,我的代码会解析错误。这是因为我在匹配链接时使用了 (?:png|jpe?g|gif) 来排除图片链接,但是没有考虑到没有扩展名的情况。

为了解决这个问题,我们可以使用 os.path.splitext 函数来获取链接的扩展名,然后根据是否有扩展名来判断是否为图片链接。改进后的代码如下:

import re, os

# Markdown文本
markdown_text = 'This is **bold** and this is *italic*. This is [[source code] xxx](https://example.com). Another [link](https://example.org). And an image: ![image desc](https://example.com/image)'

# 匹配粗体
bold_pattern = r'\*\*(.*?)\*\*'
markdown_text = re.sub(bold_pattern, r'<strong>\1</strong>', markdown_text)

# 匹配斜体
italic_pattern = r'\*(.*?)\*'
markdown_text = re.sub(italic_pattern, r'<em>\1</em>', markdown_text)

# 匹配链接(排除图片链接)
link_pattern = r'\[([^\[\]]+)\]\((https?://[^\s]+|/[^/\s]+/[^\s]+)\)'
markdown_text = re.sub(link_pattern, lambda m: f'< a href=" ">{m.group(1)}</ a>', markdown_text)

# 解析图片链接
image_pattern = r'!\[([^]]*)]\(([^)]+)\)'
markdown_text = re.sub(image_pattern, lambda m: f'< img src="{m.group(2)}" alt="{m.group(1)}">' if os.path.splitext(m.group(2))[1][1:] in ['png', 'jpg', 'jpeg', 'gif'] else m.group(0), markdown_text)

print(markdown_text)

输出结果应该是:

This is <strong>bold</strong> and this is <em>italic</em>. This is < a href="https://example.com">[source code] xxx</ a>. Another < a href="https://example.org">link</ a>. And an image: < img src="https://example.com/image" alt="image desc">

这样,即使图片链接没有扩展名,也能正确地解析了。如果还有其他问题,请随时联系我。

ROUND 0x06

实际上我知道这个最好的解决方案是后向否定断言,就是(?<!!)。它却搞出来这么多代码。
所以我尝试直接提示它:

问题:

请尝试用后向否定断言,也就是

(?<!!)\[.+?\]\(.+?\)

来匹配链接,并修改你的代码


回答:

非常感谢您的建议!使用后向否定断言的确是一个很好的选择,可以更精准地匹配不包含图片链接的链接。

修改后的代码如下:

import re

# Markdown文本
markdown_text = 'This is **bold** and this is *italic*. This is [[source code] xxx](https://example.com). Another [link](https://example.org). And an image: ![image desc](https://example.com/image)'

# 匹配粗体
bold_pattern = r'\*\*(.*?)\*\*'
markdown_text = re.sub(bold_pattern, r'<strong>\1</strong>', markdown_text)

# 匹配斜体
italic_pattern = r'\*(.*?)\*'
markdown_text = re.sub(italic_pattern, r'<em>\1</em>', markdown_text)

# 匹配链接(排除图片链接)
link_pattern = r'(?<!\!)\[([^\[\]]+)\]\((https?://[^\s]+|/[^/\s]+/[^\s]+)\)'
markdown_text = re.sub(link_pattern, lambda m: f'< a href=" ">{m.group(1)}</ a>', markdown_text)

# 解析图片链接
image_pattern = r'!\[([^]]*)]\(([^)]+)\)'
markdown_text = re.sub(image_pattern, r'< img src="\2" alt="\1">' if os.path.splitext(m.group(2))[1][1:] in ['png', 'jpg', 'jpeg', 'gif'] else m.group(0), markdown_text)

print(markdown_text)

输出结果应该和之前一样,但是现在我们使用了 (?<!\!) 来排除掉图片链接,这样就能更精准地匹配了。

再次感谢您的建议!如果还有其他问题,请随时联系我。


终于搞对了,但是这还只是一个 BUG,都这么费劲,要是修完解析器里面所有 BUG 不得累到吐血。还不如我自己思考更快。

总结

ChatGPT 对于大众的东西效果较好,但是小众的就不灵了。另外 ChatGPT 的结果仅仅是能用,并且没有考虑诸多边界情况,要想在生产环境中使用还需要很多 DEBUG。

这可能也取决于它的输入数据质量。绝大多数程序员都是用框架写应用这种比较 LOW 的工作,并没有多少人折腾 DSL 写编译器或者解析器啥的。

标签:解析器,Markdown,text,markdown,link,https,pattern,ChatGPT,example
From: https://www.cnblogs.com/apachecn/p/17376844.html

相关文章

  • 好用的markdown语法
    去掉表格边框TimeLengthSpeedMassMillisecondMillimetreKilometreperhourMilligramSecondCentimetreFootpersecondGramMinuteInchMilesperhourOuncehtmlcss文本分散对齐,两端对齐2222333444https://m.php.cn/article/525353.......
  • ChatGPT最全提示词Prompts总结,看这一篇就够了!
    以下几乎涵盖了各类人群想要使用ChatGPT的所有提示词,需要的朋友可以直接复制粘贴使用。从翻译到整理耗费超过2个小时,如果内容对大家有帮助,请不要吝啬你们的喜欢、点赞、关注~​如何正确的提问?担任创业技术律师我将要求您准备一页纸的设计合作伙伴协议草案,该协议是一家拥有I......
  • markdown基础语法
    markdown演示内容二级标题三级标题四级标题五级标题说明内容+无序列表+无序列表+无序列表1.有序列表2.有序列表3.有序列表//代码块<div>htmltag</div>......
  • ChatGPT背后的打工人:你不干,有的是AI干
    AI“出圈”如今,数字技术发展速度惊人,AI提高了社会生产效率,更真切地冲击到原有的生产秩序。年初AI技术的爆发,让国内看到了进一步降本增效的希望。国内多家互联网企业相继推出类ChatGPT产品,复旦大学邱锡鹏教授团队发布国内第一个对话式大型语言模型MOSS,度推出类ChatGPT产品“文心一......
  • 《花雕学AI》31:ChatGPT--用关键词/咒语/提示词Prompt激发AI绘画的无限创意!
    你有没有想过用AI来画画?ChatGPT是一款基于GPT-3的聊天模式的AI绘画工具,它可以根据你输入的关键词/咒语/提示词Prompt来生成不同风格和主题的画作。Prompt是一些简短的文字,可以用来指导ChatGPT的创作过程。在这篇文章中,我将展示一些用ChatGPT和不同的Prompt创造出来的有趣和创意的A......
  • chatgpt代写---五一回家人太多了
    五一小长假,让很多人终于有机会回家探亲。但是,对于我们这样的人来说,出门旅游或回家探亲,确实面临着一个非常困扰的问题:人太多了!以南京为例,今年的五一假期,回家探亲的人数可谓是爆棚。不论是在车站还是在机场,都人满为患。到处都是人头攒动,交通堵塞,难免会让人产生一些怨念。事实上,中......
  • chatgpt接口开发笔记2生成图片接口
    chatgpt接口开发笔记2生成图片接口chatgpt的生成图片接口,可以根据用户的描述来生成满足用户意愿的图片1、了解接口参数接口地址:POSThttps://api.openai.com/v1/images/generations下面是接口文档描述内容curlhttps://api.openai.com/v1/images/generations\-H"Co......
  • MarkDown学习
    标题#+空格+标题名字几个#就是几级标题字体粗体粗体两边各加两个*Hello,Word!斜体两边各加一个*Hello,Word!斜体加粗两边各加三个*Hello,Word!删除线两边各·加两个~Hello,Word!引用用一个大于号表示>该资源引用自狂神说Java分割线分割线可以用三个-减......
  • 《花雕学AI》ChatGPT的工作效率神器:110个适应各种情境的高效技巧
    实用技巧分类目录一、最佳ChatGPT4提示二、最佳写作和内容创作ChatGPT提示三、最佳趣味性ChatGPT提示四、最佳网络开发的ChatGPT提示五、最佳音乐主题ChatGPT提示六、最佳职业主题ChatGPT提示七、最佳用于教育的ChatGPT提示八、最佳用于市场营销的ChatGPT提示九、最佳游戏主题Cha......
  • 基于ChatGPT的文档知识库客服系统-支持上传网址/文本/docx等数据
    现在,很多公司都有自己的内容知识库,会产生大量的碎片话的内部知识,但是这样内部知识难以整合搜索。我开发的文档知识库客服系统gofly.v1kf.com,可以应用于企业内部知识库管理,用户可以使用自然语言提问,让ChatGPT自动归纳总结企业知识信息,帮助员工快速获取所需知识,提升资源流转效率......