/** * 行政区划展示格式化(仅展示层,不改动后端存储值)。 * * 需求:省 / 市 / 区县之间要有空格隔开,避免「上海市浦东新区」「广西壮族自治区南宁市邕宁区」挤成一坨。 * 与全站既有规则保持一致(公路地址按「市 区县」展示,省/自治区不重复展示): * 上海市浦东新区 -> 上海市 浦东新区 * 广西壮族自治区南宁市邕宁区 -> 南宁市 邕宁区 * 梅州市梅县区 -> 梅州市 梅县区 * * 非纯行政区划串(站点名「南宁站」「广州南站」、含街道门牌的详细地址等)原样返回,不做任何改动。 */ // 行政区划后缀:长后缀在前,避免「自治区」被截成「区」、「自治州」被截成「州」 const REGION_SUFFIXES = [ '特别行政区', '自治区', '自治州', '自治县', '自治旗', '开发区', '新区', '林区', '矿区', '地区', '省', '市', '州', '盟', '区', '县', '旗', ]; // 省级区划:展示时不在区划链首重复(「广西壮族自治区南宁市邕宁区」-> 「南宁市 邕宁区」) const PROVINCE_SUFFIX = /(?:省|自治区|特别行政区)$/; /** * 从文本头部匹配第一个行政区划片段。 * 特例:「梅州市」州后紧跟市,并入同一片段;「梅县区」县/旗后紧跟区,并入同一片段。 * @param {string} text 已去除空白的文本 * @returns {string} 片段,未匹配到返回 '' */ function matchRegionToken(text) { for (let end = 0; end < text.length; end += 1) { const prefix = text.slice(0, end + 1); const suffix = REGION_SUFFIXES.find(item => prefix.endsWith(item)); if (!suffix) continue; const next = text[end + 1] || ''; if ((suffix === '州' || suffix === '盟') && next === '市') continue; if ((suffix === '县' || suffix === '旗') && next === '区') return text.slice(0, end + 2); return prefix; } return ''; } /** * 按行政区划后缀把文本切成区划片段。 * @param {string} value 原值 * @returns {string[]|null} 整串都是行政区划时返回片段数组,否则返回 null */ export function splitRegionTokens(value) { const text = String(value ?? '').replace(/\s+/g, ''); if (!text) return null; const tokens = []; let rest = text; while (rest) { const token = matchRegionToken(rest); if (!token) return null; tokens.push(token); rest = rest.slice(token.length); } return tokens; } /** * 行政区划串按「市 区县」展示,省/自治区不重复展示。 * @param {string} value 原值 * @returns {string} 含空格的展示值;非纯行政区划串原样返回 */ export function formatRegionAddress(value) { const text = String(value ?? '').trim(); if (!text) return ''; const tokens = splitRegionTokens(text); if (!tokens || !tokens.length) return text; const display = PROVINCE_SUFFIX.test(tokens[0]) ? tokens.slice(1) : tokens; return (display.length ? display : tokens).join(' '); } export default formatRegionAddress;