
本文介绍在 JavaScript 中实现日期格式化时,如何通过正则边界匹配和替换顺序控制,避免短占位符(如 dd)被长占位符(如 dddd)的替换过程意外污染,从而确保 ddd dd-mm-yyyy 等模板能正确输出 Sun 05-11-2023。
本文介绍在 javascript 中实现日期格式化时,如何通过正则边界匹配和替换顺序控制,避免短占位符(如 `dd`)被长占位符(如 `dddd`)的替换过程意外污染,从而确保 `ddd dd-mm-yyyy` 等模板能正确输出 `sun 05-11-2023`。
字符串替换冲突是模板引擎开发中常见的陷阱:当多个占位符存在包含关系(如 dd 是 dddd 的子串),且采用简单 .replace() 逐个替换时,先替换 dd 会导致后续 dddd 匹配失败或误替——例如 dddd 被提前拆解为 dd + dd,再被分别替换成日期数字,最终变成 05d 05-11-2023。
根本解法有两个关键原则:
✅ 优先替换更长的占位符(如 dddd → ddd → yyyy → dd),避免短串干扰长串原始结构;
✅ 使用单词边界 正则限定符,确保只匹配完整、独立的占位符,而非子串。例如 dd 不会匹配 dddd 中的 dd。
以下是优化后的 Date.prototype.format 实现:
Date.prototype.format = function (template) {
const replacements = {
'yyyy': this.getFullYear(),
'mm': (this.getMonth() + 1).toString().padStart(2, '0'),
'dd': this.getDate().toString().padStart(2, '0'),
'HH': this.getHours().toString().padStart(2, '0'),
'ii': this.getMinutes().toString().padStart(2, '0'),
'ss': this.getSeconds().toString().padStart(2, '0'),
'dddd': this.toLocaleString(window.navigator.language, { weekday: 'long' }),
'ddd': this.toLocaleString(window.navigator.language, { weekday: 'short' }),
};
// 按长度降序排列 key,确保 'dddd' 在 'ddd' 之前处理
const sortedKeys = Object.keys(replacements).sort((a, b) => b.length - a.length);
return sortedKeys.reduce((str, key) => {
const regex = new RegExp(`\b${key}\b`, 'g');
return str.replace(regex, replacements[key]);
}, template);
};
⚠️ 注意事项:
- 要求占位符前后为单词边界(如空格、标点、字符串起止),因此模板中占位符应保持独立(如 ddd-dd 中的 ddd 仍可匹配,但 addd 中的 ddd 不会误匹配);
- 若需支持非边界场景(如嵌入在字母中),可改用 (?
- 扩展性提示:将 replacements 提取为配置对象后,便于后续添加 MMM(月份缩写)、MM(月份数字)等新格式符,且无需修改核心逻辑。
实际调用示例:
const now = new Date(2023, 10, 5, 14, 30, 45); // 2023-11-05
console.log(now.format('dddd, dd-mm-yyyy HH:ii:ss'));
// 输出:Sunday, 05-11-2023 14:30:45(取决于系统语言)
console.log(now.format('ddd dd-mm-yyyy'));
// 输出:Sun 05-11-2023 ✅ 再无冲突
该方案兼顾健壮性与可维护性,是构建轻量级格式化工具的推荐实践。










