【小黄碎碎念】如何解析和替换字符串中的 Markdown 文本?正则表达式与 flexmark-java 库

前言

 本周,笔者将之前的基于 Servlet 的个人博客项目进行了迭代,基于 SpringBoot + SpringMVC + Mybatis + Redis 进行实现。额外实现密码的明文加密处理(加盐算法)、修改随笔、随笔主页等功能,并将 session 存储到 Redis 中持久化,同时额外实现分页功能并使用对 AOP 思想对用户登录身份验证模块进行升级。升级成为随笔分享平台,当然目前还在迭代中。emmmm,具体后面会出文章详细介绍。这里先说说遇到的问题:
问题图片
可以发现:在随笔的摘要信息中,形如 # 这样的 markdown 标签也一并展示在了随笔摘要信息中。

怎么解决呢? 很显然,一种是自己解决,一种是依赖 api:

  • 使用正则表达式对文章正文中的所有 markdown 标签进行匹配,然后使用空字符进行替换;
  • 使用 flexmark-java库来解析和转换 Markdown 文本。

下面,笔者将对两种方式分别进行讲解,并使用正则表达式的方式处理个人随笔系统中的该问题。我们接着往下看~


文章目录

  • 前言
  • 1 正则表达式替换 Markdown 文本
    • 1.1 正则表达式简介
    • 1.2 具体实现
  • 2 flexmark-java库解析和转换 Markdown 文本
  • 3 实战:对随笔系统中的摘要信息处理


1 正则表达式替换 Markdown 文本

1.1 正则表达式简介

正则表达式是一种强大的模式匹配工具,可以用于查找和替换文本中的特定模式。当涉及到在Java中使用正则表达式时,可以使用java.util.regex包提供的类来进行模式匹配、查找和替换操作。以下是一些常用的类和方法:

  1. Pattern类:Pattern类用于表示正则表达式模式。可以使用Pattern.compile()方法将正则表达式编译为一个Pattern对象。

    String regex = "\\d+"; // 匹配一个或多个数字
    Pattern pattern = Pattern.compile(regex);
    
  2. Matcher类:Matcher类用于进行模式匹配操作。可以使用Matcher.matches()方法检查整个输入字符串是否与模式匹配,或使用Matcher.find()方法在输入字符串中查找下一个匹配项。

    String input = "Hello 123 World";
    Matcher matcher = pattern.matcher(input);
    if (matcher.find()) {
        System.out.println("匹配到数字:" + matcher.group());
    }
    
  3. String类的正则表达式方法:String类提供了一些便捷的方法来处理正则表达式,如String.matches()String.replaceAll()String.split()

    String input = "Hello 123 World";
    if (input.matches("\\d+")) {
        System.out.println("输入字符串是一个数字");
    }
    
    String replaced = input.replaceAll("\\d+", "###");
    System.out.println("替换后的字符串:" + replaced);
    
    String[] parts = input.split("\\s+"); // 使用空白字符分割字符串
    System.out.println("分割后的字符串数组:" + Arrays.toString(parts));
    

具体可参考Java官方文档中关于正则表达式的部分:Java 正则表达式

1.2 具体实现

import java.util.regex.Pattern;

public class MarkdownUtils {
    public static String removeMarkdownTags(String markdown) {
        // 匹配Markdown标签的正则表达式
        String regex = "\\*\\*|__|\\*|_|~~|`|\\[\\]|\\(|\\)|\\{|\\}|\\[|\\]|#|\\+|-|\\.|!";
        // 使用空字符串替换Markdown标签
        String result = Pattern.compile(regex).matcher(markdown).replaceAll("");
        return result;
    }
}

在上面的示例中,removeMarkdownTags方法接受一个Markdown格式的字符串作为输入,并使用正则表达式将Markdown标签替换为空字符串,从而去除Markdown标签。


2 flexmark-java库解析和转换 Markdown 文本

首先,需要在项目中添加flexmark-java库的依赖。如果使用 Maven,可以在pom.xml文件中添加以下依赖项:

<dependencies>
    <dependency>
        <groupId>com.vladsch.flexmark</groupId>
        <artifactId>flexmark-all</artifactId>
        <version>0.62.2</version>
    </dependency>
</dependencies>

然后就可以使用flexmark-java库来解析Markdown文本并获取纯文本内容,如下所示:

import com.vladsch.flexmark.html.HtmlRenderer;
import com.vladsch.flexmark.parser.Parser;

public class MarkdownUtils {
    public static String removeMarkdownTags(String markdown) {
        Parser parser = Parser.builder().build();
        HtmlRenderer renderer = HtmlRenderer.builder().build();

        // 将Markdown文本解析为HTML
        String html = renderer.render(parser.parse(markdown));

        // 使用Jsoup库从HTML中获取纯文本内容
        String plainText = org.jsoup.Jsoup.parse(html).text();

        return plainText;
    }

    public static void main(String[] args) {
        String markdown = "**Hello** _world_!";
        String plainText = removeMarkdownTags(markdown);
        System.out.println(plainText);  // 输出: Hello world!
    }
}

在上面的示例中,使用flexmark-java库将Markdown文本解析为HTML,然后使用Jsoup库从HTML中提取纯文本内容。


3 实战:对随笔系统中的摘要信息处理

在这里,笔者使用正则表达式的方式对随笔摘要信息进行处理。
首先,创建一个 MarkdownUtils 工具类,该类就是专门用于处理 Markdown 文本的:

  1. 对摘要进行去除 markdown 标签处理;
  2. 摘要只截取文章正文前的 n 个字符;

MarkdownUtils.java

import java.util.regex.Pattern;

/**
 * @author 兴趣使然黄小黄
 * @date 2023/7/23 23:18
 * 用于处理文章列表的文章摘要信息
 */
public class MarkdownUtils {

    // 匹配Markdown标签的正则表达式
    private static String regex = "\\*\\*|__|\\*|_|~~|`|\\[\\]|\\(|\\)|\\{|\\}|\\[|\\]|#|\\+|-|\\.|!";

    /**
     * 对摘要进行去 markdown 标签处理
     */
    public static String removeMarkdownTags(String markdown, int n) {
        // 先对 markdown 字符串进行截取
        markdown = preprocessingString(markdown, n);
        // 使用空字符串替换Markdown标签并返回
        return Pattern.compile(regex).matcher(markdown).replaceAll("");
    }

    /**
     * 截取正文的前 n 个字符作为摘要
     */
    private static String preprocessingString(String s, int n) {
        if (s == null || s == "" || n <= 0) {
            return "";
        }
        String result = "";
        if (n >= s.length()) {
            result = s.substring(0, s.length());
        } else {
            result = s.substring(0, n);
        }
        return result;
    }
}

编写完代码后,我们进行简单的 单元测试:

@SpringBootTest
class MarkdownUtilsTest {
    @Test
    void removeMarkdownTags() {
        String markdown = "**Hello** _world_";
        String result = MarkdownUtils.removeMarkdownTags(markdown, 256);
        System.out.println(result);
        Assertions.assertEquals("Hello world", result);
    }
}

单元测试结果如下:
单元测试结果
测试没问题后,我们可以着手对项目中的返回文章列表部分进行处理。

在项目中,获取个人随笔列表信息的 url 为 /art//mylist , 因此找到对应的 controller,只需要对获取的文章信息对象的列表的正文进行处理后再返回:
bug修改

为了程序后期的维护,我们把摘要的最大字符长度放在了一个公共类进行保存:
公共变量

最后,我们撰写一个很长很长的随笔来看看 # 是否会被处理,文章是否会被截取吧~结果如下:
结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/44369.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

App测试中ios和Android的区别

1、Android长按home键呼出应用列表和切换应用&#xff0c;然后右滑则终止应用&#xff1b; 2、多分辨率测试&#xff0c;Android端20多种&#xff0c;ios较少&#xff1b; 3、手机操作系统&#xff0c;Android较多&#xff0c;ios较少且不能降级&#xff0c;只能单向升级&…

ffmpeg中filter_query_formats函数解析

ffmpeg中filter_query_formats主要起一个pix fmt引用指定的功能。 下下结论&#xff1a; 先看几个结构体定义&#xff1a; //删除了一些与本次分析不必要的成员 struct AVFilterLink {AVFilterContext *src; ///< source filterAVFilterPad *srcpad; ///<…

Feign远程调用如何携带form url

这是一个需要携带参数在form url上的请求&#xff0c;正常调用方式是这样的 响应&#xff1a; 在Feign中&#xff0c;应该怎么调用呢?? 定义OpenFeignClient接口 FeignClient(value "client-service", url "http://127.0.0.1/api") public interface…

pytorch工具——认识pytorch

目录 pytorch的基本元素操作创建一个没有初始化的矩阵创建一个有初始化的矩阵创建一个全0矩阵并可指定数据元素类型为long直接通过数据创建张量通过已有的一个张量创建相同尺寸的新张量利用randn_like方法得到相同尺寸张量&#xff0c;并且采用随机初始化的方法为其赋值采用.si…

记一次简单的MySql注入试验

试验环境&#xff1a; 1.已经搭建好的php服务器&#xff0c;并可以通过访问到localhost/index.php&#xff1b; 2.已经安装好数据库&#xff0c;并创建表test&#xff0c;表内有name、age等字段&#xff0c;并随便创建几个假数据用于测试&#xff1b;如图&#xff1a; 开始测…

万向节死锁

要理解万向节死锁的产生原因&#xff0c;首先要理解欧拉角变换&#xff0c;欧拉角变换是基于最初始的坐标进行变换而非变换后的坐标进行变换。 欧拉角变换需要空间中的三个角&#xff08;即变换后每个轴的偏移量&#xff09;&#xff0c;另外还有每个轴的变换顺序。值得注意的…

安装:【vue】npm install -g @vue/cli出现错误

安装Vue脚手架&#xff0c;cli就是Command Line Interface 命令行接口 工具 进行到npm install -g vue/cli这一步出现错误&#xff0c;操作步骤如下&#xff1a; 1.通过 wins打开开始栏的搜索框&#xff0c;输入cmd&#xff0c;管理员身份运行 2.先下载node.js 不知道有没有…

应用案例 | 实现第三方控制系统下HART智能设备的集中管理与维护

一 背景 在过程工业向数字化转型的过程中&#xff0c;设备管理系统扮演者着关键的角色——帮助企业集中管理和监控现场设备&#xff0c;并实现全面的设备管理和维护。通过实时监测和控制设备的运行状态、性能和健康状况&#xff0c;设备管理系统能够提前发现设备故障、减少生产…

Transformer+医学图像最新进展【2023】

Transformer主要用于自然语言处理领域。近年来,它在计算机视觉(CV)领域得到了广泛的应用。医学图像分析(MIA,Medical image analysis)作为机器视觉(CV,Computer Vision)的一个重要分支,也极大地受益于这一最先进的技术。 机构:新加坡国立大学机械工程系、中山大学智能系…

链动2+1营销系统开发模式深度解析

链动21模式其实是一种针对快消品行业的营销模式&#xff0c;主要逻辑就是用薄利多销丰厚返利的方式来吸引客户&#xff0c;同时快速裂变团队。 这个模式的玩法也很简单&#xff0c;只有代理和老板两种身份&#xff0c;代理身份是用户购买499元产品可以解锁&#xff0c;同时享受…

es通过rest接口_search、_delete_by_query查询与删除数据

1、rest接口查询数据 rest查询: http://localhost:9200/index_name/_search 查询表达式&#xff1a; {"query": {"wildcard": {"accountID": {"value": "v*"}}} }postman请求截图&#xff1a; 2、使用Rest接口删除数据 …

Mysql表的查找进阶

重点细节知识&#xff1a;NULL是表示表里这个格子是空着的&#xff0c;NULL参与各种运算都是->false&#xff0c;但是只有这个才是可以用NULL等于NULL成功的 <>。,看一下&#xff0c;下图的区别&#xff0c;下面的是连空也算上了 补充一个is 用法&#xff0c;和上面语…

python实现远程服务器的操作

前言 测试过程中经常会遇到需要将本地的文件上传到远程服务器上&#xff0c;或者需要将服务器上的文件拉到本地就行操作&#xff0c;以前安静经常会用到xftp工具。今天介绍一种python库Paramiko&#xff0c;可以帮助我们通过代码的方式进行完成对远程服务器的上传和下载操作。…

OpenCV for Python 实战(一):获取图片拍摄GPS地址并自动添加水印

Hello 我们在OpenCV每天的基础博客当中已经更新了很多了&#xff0c;那么今天我们就来结合前几天的内容。做一个获取属性然后添加对应属性的水印。那让我们赶快开始吧~ 文章目录 图片EXIFPython 获取EXIFexifread库使用方法转换成文字地址 添加水印cv2.putText() 每日总结 图片…

了解应用层

应用层 1. 概述2. 应用程序组织方式2.1 C/S方式2.1 P2P方式 3. 动态主机配置协议DHCP3.1 DHCP工作流程 4. 域名系统DNS4.1 域名结构4.2 域名分类4.3 域名服务器4.3.1 分类 4.4 DNS域名解析过程 5. 文件传输协议FTP5.1 FTP工作流程 6. 电子邮件系统6.1 邮件信息格式6.2 简单邮件…

信息的表示与处理 (深入理解计算机系统第二章)

刚学习这本书没多久&#xff0c;感觉里面讲的东西挺多的&#xff0c;前后的关联性比较强。学着后面的还需要看看前的才可以更好的理解。 2.1信息存储 无符号(unsigned) 编码是基于传统的二进制表示法的&#xff0c;表示大于或者等于零的数字。 二进制补码(twos-complement)编…

存储过程——用户自定义变量、局部变量

1.用户自定义变量 在会话一定义的变量在会话二中是用不了的。 使用set指令定义变量,并为变量赋值&#xff0c;mysql中赋值推荐使用 :&#xff0c;因为在mysql中没有这个比较运算&#xff0c;也带有比较运算的功能&#xff0c;因此赋值运算推荐使用 : set myname itcast; se…

软件测试面试题及答案【史上最全】

以下是软件测试相关的面试题及答案&#xff0c;欢迎大家参考! 1、你的测试职业发展是什么? 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&…

边缘提取总结

边缘提取&#xff1a;什么是边缘&#xff1f; 图象的边缘是指图象局部区域亮度变化显著的部分&#xff0c;该区域的灰度剖面一般可以 看作是一个阶跃&#xff0c;既从一个灰度值在很小的缓冲区域内急剧变化到另一个灰度相 差较大的灰度值。 边缘有正负之分&#xff0c;就像…

uni-app:实现账号密码登录,并且实现当页面登录过该账号在下次登录时无需再输入账号密码(本地缓存实现)

效果 前端代码 一、完整代码 <template><view><view class"all"><view class"title"><image :src"title_login" alt"图片损坏" /></view><form class"login-form" submit"fo…