utils.js 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. /**
  2. * 替换字符串中的占位符
  3. * 支持多种插值语法:
  4. * 1. 数字索引:{0}, {1}, {2}...
  5. * 2. 命名参数:{name}, {age}...
  6. * 3. 对象属性:{user.name}, {user.age}...
  7. *
  8. * @param template 模板字符串,如 "Hello {0}, welcome to {1}" 或 "Hello {name}, welcome to {place}"
  9. * @param values 要替换的值,可以是数组、对象或混合
  10. * @returns 替换后的字符串
  11. */
  12. export function interpolateTemplate(template, values) {
  13. if (!template || typeof template !== 'string') {
  14. return template;
  15. }
  16. // 如果没有提供值,直接返回模板
  17. if (values === undefined || values === null) {
  18. return template;
  19. }
  20. // 处理数组形式的参数
  21. if (Array.isArray(values)) {
  22. return template.replace(/{(\d+)}/g, (match, index) => {
  23. const numIndex = parseInt(index, 10);
  24. return values[numIndex] !== undefined ? String(values[numIndex]) : match;
  25. });
  26. }
  27. // 处理对象形式的参数
  28. if (typeof values === 'object') {
  29. return template.replace(/{([^}]+)}/g, (match, key) => {
  30. // 处理嵌套对象属性,如 {user.name}
  31. const keys = key.trim().split('.');
  32. let value = values;
  33. for (const k of keys) {
  34. if (value && typeof value === 'object' && k in value) {
  35. value = value[k];
  36. } else {
  37. return match; // 如果找不到对应的值,保持原样
  38. }
  39. }
  40. return value !== undefined ? String(value) : match;
  41. });
  42. }
  43. // 如果values不是数组也不是对象,直接返回模板
  44. return template;
  45. }
  46. /**
  47. * 增强的插值函数,支持更复杂的插值语法
  48. * @param template 模板字符串
  49. * @param values 插值参数
  50. * @param options 配置选项
  51. * @returns 替换后的字符串
  52. */
  53. export function advancedInterpolate(template, values, options = {}) {
  54. if (!template || typeof template !== 'string') {
  55. return template;
  56. }
  57. const {
  58. fallback = '', // 当找不到对应值时的默认值
  59. prefix = '{', // 插值前缀
  60. suffix = '}', // 插值后缀
  61. escape = false // 是否转义HTML
  62. } = options;
  63. // 构建正则表达式
  64. const regex = new RegExp(`${escapeRegExp(prefix)}([^${escapeRegExp(suffix)}]+)${escapeRegExp(suffix)}`, 'g');
  65. return template.replace(regex, (match, key) => {
  66. const trimmedKey = key.trim();
  67. let value = getNestedValue(values, trimmedKey);
  68. if (value === undefined) {
  69. return fallback || match;
  70. }
  71. // 转换为字符串
  72. let result = String(value);
  73. // HTML转义
  74. if (escape) {
  75. result = result
  76. .replace(/&/g, '&')
  77. .replace(/</g, '&lt;')
  78. .replace(/>/g, '&gt;')
  79. .replace(/"/g, '&quot;')
  80. .replace(/'/g, '&#39;');
  81. }
  82. return result;
  83. });
  84. }
  85. /**
  86. * 获取嵌套对象的值
  87. * @param obj 对象
  88. * @param path 路径,如 'user.name' 或 '0.name'
  89. * @returns 值
  90. */
  91. function getNestedValue(obj, path) {
  92. if (!obj || typeof obj !== 'object') {
  93. return undefined;
  94. }
  95. const keys = path.split('.');
  96. let value = obj;
  97. for (const key of keys) {
  98. if (value && typeof value === 'object') {
  99. // 如果是数字索引,尝试作为数组访问
  100. if (/^\d+$/.test(key)) {
  101. const index = parseInt(key, 10);
  102. value = Array.isArray(value) ? value[index] : value[key];
  103. } else {
  104. value = value[key];
  105. }
  106. } else {
  107. return undefined;
  108. }
  109. }
  110. return value;
  111. }
  112. /**
  113. * 转义正则表达式特殊字符
  114. * @param string 字符串
  115. * @returns 转义后的字符串
  116. */
  117. function escapeRegExp(string) {
  118. return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
  119. }