MessageFormat中单引号是语法控制符而非普通字符,用于转义占位符或表示字面量:两个单引号''输出一个',单个成对单引号包裹内容跳过解析,孤立单引号被忽略;模板需预处理将独立'替换为'';花括号需用单引号包裹以避免解析错误;参数须严格匹配占位符索引、类型与数量。

MessageFormat.format 里单引号不是普通字符,而是语法控制符——它会“吃掉”后面紧邻的占位符或特殊符号,导致 {0}、{1,date} 等直接原样输出,不被替换。这不是 bug,是设计机制,但容易踩坑。
单引号的三种作用必须分清
在 MessageFormat 模式字符串中,单引号有且仅有以下三种合法用法:
-
两个连续单引号 '' 表示一个字面量单引号:如
"用户''s name is {0}"→ 输出用户's name is Alice -
单个单引号 ' 开头 + 内容 + 单引号 ' 结尾,整体被当作纯文本(跳过解析):如
"'{0} is not parsed'"→ 输出{0} is not parsed({0} 不替换) -
单个单引号出现在非起始位置(如中间或末尾),会被直接忽略(除非成对):如
"He said 'hello' to {0}"→ 实际等价于"He said hello to {0}",单引号消失
所有含单引号的模板都必须预处理
如果原始模板来自配置、数据库或前端输入(比如邮件模板、JSON 字段、SQL 片段),里面天然带英文单引号,不能直接传给 format()。必须先做转义:
- 把每个独立的
'替换成''(两个单引号) - 注意:只替换字面量单引号,不要碰已有的
''或'{0}'这类结构——否则会变成'''{0}''',反而出错 - 推荐写法:
String safePattern = originalPattern.replace("'", "''"); - 再调用:
MessageFormat.format(safePattern, args)
花括号 { } 出现在单引号外时也要小心
如果模板里要显示原始花括号(比如 JSON、正则、SQL),又不想被当成占位符解析,必须用单引号包裹:
- 错误写法:
"{id: {0}, name: {1}}"→ 报错can't parse argument number - 正确写法:
"'{id: {0}, name: {1}}'"或更稳妥的"'{id: ''{0}'', name: ''{1}''}'" - 关键点:外层单引号让整个内容当作文本;内部若还需显示单引号,则用
''表示
参数传入必须严格匹配占位符定义
单引号问题常掩盖另一个根本错误:参数与占位符不一致。确认以下三点:
- 占位符索引从 0 开始,且建议连续使用(避免 {0}、{2} 跳号)
- 传参必须是
Object[]类型,不能直接传多个 Object(format("{}", "a", "b")会报错,得写format("{}", new Object[]{"a", "b"})) - 类型声明要匹配,例如
{0,number}就不能传 String,否则抛Cannot format given Object as a Number










