
本文介绍如何使用正则表达式从含中英文引号(" 和 ”)的字符串中安全提取引号包裹的主体名称,并自动移除引号本身及引号之后的所有冗余文本。
本文介绍如何使用正则表达式从含中英文引号(`"` 和 `”`)的字符串中安全提取引号包裹的主体名称,并自动移除引号本身及引号之后的所有冗余文本。
在实际业务系统(如银行名称解析、金融报文处理)中,常遇到类似 "KAPİTAL BANK" AÇIQ SƏHMDAR CƏMİYYƏTİ 或 BANK "BTB” AÇIQ SƏHMDAR CƏMİYYƏTİ 这类混合使用直角双引号(U+0022)与右向弯引号(U+201D)的字符串。目标并非简单删除所有引号,而是精准捕获首对匹配引号之间的内容,并丢弃引号本身及后续全部字符——即从 ( BANK "BTB” AÇIQ ... ) 提取为 BANK BTB。
原始代码存在多个关键问题:
- 使用两个独立 Pattern 分别匹配不同引号,但未考虑引号成对出现的语义,且 while (m.find()) 会重复替换,逻辑错乱;
- m.group(1) 直接赋值覆盖原字符串,导致上下文丢失;
- 未处理引号不闭合、嵌套或无引号等边界情况,鲁棒性差。
✅ 推荐方案:单次正则替换 + 前后锚定
使用 String.replaceAll() 配合精心设计的正则,一次性完成「定位首对引号 → 提取内部文本 → 拼接前置非引号部分 → 截断后续所有内容」:
String input = "BANK \"BTB” AÇIQ SƏHMDAR CƏMİYYƏTİ";
String output = input.replaceAll("^([^\"”]*)[\"”]([^\"”]+)[\"”].*$", "$1$2");
System.out.println(output); // 输出:BANK BTB? 正则详解:
- ^:字符串开头锚点;
- ([^\"”]*):捕获组1 —— 匹配引号前任意数量的非引号字符(如 "BANK " 中的 BANK);
- [\"”]:匹配任一类型左引号(" 或 ”);
- ([^\"”]+):捕获组2 —— 匹配引号内至少一个非引号字符(即目标名称 BTB);
- [\"”]:匹配对应的右引号(无需严格配对,因后续 .* 会吞掉一切);
- .*$:匹配右引号后所有剩余内容直至结尾;
- "$1$2":仅保留前置部分 + 引号内内容,彻底丢弃引号及后续文本。
⚠️ 注意事项:
立即学习“Java免费学习笔记(深入)”;
- 若字符串不含任何引号,该正则不匹配,output 等于原 input,行为安全;
- 若仅有一个引号(不成对),因缺少第二个 [\"”],正则不匹配,同样保留原串;
- 如需支持单引号(')或中文全角引号(‘’),可扩展字符类为 [\"”'\u2018\u2019];
- 生产环境建议预编译 Pattern 提升性能:
private static final Pattern QUOTE_EXTRACTOR = Pattern.compile("^([^\"”]*)[\"”]([^\"”]+)[\"”].*$"); // 使用时:QUOTE_EXTRACTOR.matcher(input).replaceFirst("$1$2");
总结:避免碎片化多次匹配,应优先采用「锚定 + 全局替换」策略,用一条正则表达式明确声明输入结构与期望输出格式。这不仅代码简洁、执行高效,更具备良好的可读性与可维护性。










