更新替换变量函数

This commit is contained in:
wxzhang 2022-03-02 21:57:55 +08:00
parent 25f548535b
commit f5cac613bb
2 changed files with 84 additions and 64 deletions

View File

@ -107,9 +107,9 @@ function parseFormatters(formatters){
* 提取字符串中的插值变量 * 提取字符串中的插值变量
* @param {*} str * @param {*} str
* @param {*} isFull =true 保留所有插值变量 =false 进行去重 * @param {*} isFull =true 保留所有插值变量 =false 进行去重
* @returns {Array} [[变量名称,[]],[变量名称,[formatter,formatter,...]],...] * @returns {Array} [[变量名称,[],match],[变量名称,[formatter,formatter,...],match],...]
*/ */
function getInterpolatedVars(str,isFull=false){ function getInterpolatedVars(str){
let results = [], match let results = [], match
while ((match = varWithPipeRegexp.exec(str)) !== null) { while ((match = varWithPipeRegexp.exec(str)) !== null) {
if (match.index === varWithPipeRegexp.lastIndex) { if (match.index === varWithPipeRegexp.lastIndex) {
@ -118,17 +118,31 @@ function getInterpolatedVars(str,isFull=false){
const varname = match.groups.varname || "" const varname = match.groups.varname || ""
// 解析格式化器和参数 = [<formatterName>,[<formatterName>,[<arg>,<arg>,...]]] // 解析格式化器和参数 = [<formatterName>,[<formatterName>,[<arg>,<arg>,...]]]
const formatters = parseFormatters(match.groups.formatters) const formatters = parseFormatters(match.groups.formatters)
const varInfo = [varname,formatters] const varInfo = [varname,formatters,match]
if(isFull) { results.push(varInfo)
results.push([varname,formatters] )
}else{
if(results.findIndex(item=>item[0]===varInfo[0] && item[1].join()===varInfo[1].join()) === -1) results.push(varInfo)
}
} }
return results return results
} }
/**
* 遍历插值变量并进行替换插值变量
* @param {*} str
* @param {*} callback
* @returns
*/
function forEachInterpolatedVars(str,callback){
let result=str, match
varWithPipeRegexp.lastIndex=0
while ((match = varWithPipeRegexp.exec(result)) !== null) {
const varname = match.groups.varname || ""
// 解析格式化器和参数 = [<formatterName>,[<formatterName>,[<arg>,<arg>,...]]]
const formatters = parseFormatters(match.groups.formatters)
if(typeof(callback)==="function"){
result=result.replaceAll(match[0],callback(varname,formatters))
}
varWithPipeRegexp.lastIndex=0
}
return result
}
/** /**
* 将要翻译内容提供了一个非文本内容时进行默认的转换 * 将要翻译内容提供了一个非文本内容时进行默认的转换
* - 对函数则执行并取返回结果() * - 对函数则执行并取返回结果()
@ -220,7 +234,7 @@ function getDataTypeDefaultFormatter(scope,activeLanguage,dataType){
let formattersCache = { $activeLanguage:null} let formattersCache = { $activeLanguage:null}
function getFormatter(scope,activeLanguage,name){ function getFormatter(scope,activeLanguage,name){
if(formattersCache.$activeLanguage === activeLanguage) { if(formattersCache.$activeLanguage === activeLanguage) {
if(name in formattersCache) return formattersCache[dataType] if(name in formattersCache) return formattersCache[name]
}else{ // 当切换语言时需要清空缓存 }else{ // 当切换语言时需要清空缓存
formattersCache = { $activeLanguage:activeLanguage } formattersCache = { $activeLanguage:activeLanguage }
} }
@ -250,7 +264,7 @@ function executeFormatter(value,formatters){
for(let formatter of formatters){ for(let formatter of formatters){
if(typeof(formatter) === "function") { if(typeof(formatter) === "function") {
result = formatter(result) result = formatter(result)
}else{ // 碰到无效的格式化器时,直接返回 }else{
return result return result
} }
} }
@ -272,31 +286,41 @@ function buildFormatters(scope,activeLanguage,formatters){
let results = [] let results = []
for(let formatter of formatters){ for(let formatter of formatters){
if(formatter[0]){ if(formatter[0]){
results.push((v)=>{ const func = getFormatter(scope,activeLanguage,formatter[0])
return getFormatter(scope,activeLanguage,formatter[0])(v,...formatter[1]) if(typeof(func)==="function"){
}) results.push((v)=>{
return func(v,...formatter[1])
})
}else{// 格式化器无效或者没有定义时,查看当前值是否具有同名的方法,如果有则执行调用
results.push((v)=>{
if(typeof(v[formatter[0]])==="function"){
return v[formatter[0]].call(v,...formatter[1])
}else{
return v
}
})
}
} }
} }
return results return results
} }
/**
/** * 字符串可以进行变量插值替换
* 字符串可以进行变量插值替换 * replaceInterpolatedVars("<模板字符串>",{变量名称:变量值,变量名称:变量值,...})
* replaceInterpolatedVars("<模板字符串>",{变量名称:变量值,变量名称:变量值,...}) * replaceInterpolatedVars("<模板字符串>",[变量值,变量值,...])
* replaceInterpolatedVars("<模板字符串>",[变量值,变量值,...]) * replaceInterpolatedVars("<模板字符串>",变量值,变量值,...])
* replaceInterpolatedVars("<模板字符串>",变量值,变量值,...]) *
* - 当只有两个参数并且第2个参数是{}将第2个参数视为命名变量的字典
- 当只有两个参数并且第2个参数是{}将第2个参数视为命名变量的字典 replaceInterpolatedVars("this is {a}+{b},{a:1,b:2}) --> this is 1+2
replaceInterpolatedVars("this is {a}+{b},{a:1,b:2}) --> this is 1+2 - 当只有两个参数并且第2个参数是[]将第2个参数视为位置参数
- 当只有两个参数并且第2个参数是[]将第2个参数视为位置参数 replaceInterpolatedVars"this is {}+{}",[1,2]) --> this is 1+2
replaceInterpolatedVars"this is {}+{}",[1,2]) --> this is 1+2 - 普通位置参数替换
- 普通位置参数替换 replaceInterpolatedVars("this is {a}+{b}",1,2) --> this is 1+2
replaceInterpolatedVars("this is {a}+{b}",1,2) --> this is 1+2 -
- this == scope == { formatters: {}, ... }
this == scope == { formatters: {}, ... } * @param {*} template
* @param {*} template * @returns
* @returns */
*/
function replaceInterpolatedVars(template,...args) { function replaceInterpolatedVars(template,...args) {
const scope = this const scope = this
// 当前激活语言 // 当前激活语言
@ -306,37 +330,22 @@ function replaceInterpolatedVars(template,...args) {
// ****************************变量插值**************************** // ****************************变量插值****************************
if(args.length===1 && typeof(args[0]) === "object" && !Array.isArray(args[0])){ if(args.length===1 && typeof(args[0]) === "object" && !Array.isArray(args[0])){
// 读取模板字符串中的插值变量列表 // 读取模板字符串中的插值变量列表
// [[var1:[formatter,formatter,...]],[var2:[formatter,formatter,...]],...} // [[var1,[formatter,formatter,...],match],[var2,[formatter,formatter,...],match],...}
let interpVars = getInterpolatedVars(template)
let varValues = args[0] let varValues = args[0]
if(interpVars.length===0) return template // 没有变量插值则的返回原字符串 return forEachInterpolatedVars(template,(varname,formatters)=>{
// 开始处理插值变量 // 1. 取得格式化器函数列表
for(let [name,formatters] of interpVars){
// 1. 取得格式化器函数列表 formatters=[[格式化器名称,[参数,参数,...]][格式化器名称,[参数,参数,...]]]
const formatterFuncs = buildFormatters(scope,activeLanguage,formatters) const formatterFuncs = buildFormatters(scope,activeLanguage,formatters)
// 2. 取变量值 // 2. 取变量值
let value = (name in varValues) ? varValues[name] : '' let value = (varname in varValues) ? varValues[varname] : ''
// 3. 查找每种数据类型默认格式化器,并添加到formatters最前面默认数据类型格式化器优先级最高 // 3. 查找每种数据类型默认格式化器,并添加到formatters最前面默认数据类型格式化器优先级最高
const defaultFormatter = getDataTypeDefaultFormatter(scope,activeLanguage,getDataTypeName(value)) const defaultFormatter = getDataTypeDefaultFormatter(scope,activeLanguage,getDataTypeName(value))
if(defaultFormatter){ if(defaultFormatter){
formatterFuncs.splice(0,0,defaultFormatter) formatterFuncs.splice(0,0,defaultFormatter)
} }
// 4. 执行格式化器 // 4. 执行格式化器
value = executeFormatter(value,formatterFuncs) value = executeFormatter(value,formatterFuncs)
return value
// 5. 进行值替换 })
// 如果变量中包括|管道符,则需要进行转换以适配更宽松的写法比如data|time能匹配"data |time","data | time"等
let nameRegexp =
if(formatters.length===0){
nameRegexp = new RegExp(String.raw`\{\s*${name}\s*\}`,"gm")
}else{
nameRegexp = new RegExp(`${name}\\s*\\|\\s*${formatters.join("\\s*\\|\\s*")}`,"gm")
}
result= result.replaceAll(nameRegexp,transformToString(value))
}
}else{ }else{
// ****************************位置插值**************************** // ****************************位置插值****************************
// 如果只有一个Array参数则认为是位置变量列表进行展开 // 如果只有一个Array参数则认为是位置变量列表进行展开
@ -357,7 +366,7 @@ function replaceInterpolatedVars(template,...args) {
formatterFuncs.splice(0,0,defaultFormatter) formatterFuncs.splice(0,0,defaultFormatter)
} }
value = executeFormatter(value,formatterFuncs) value = executeFormatter(value,formatterFuncs)
result=result.replace(match,transformToString(value)) result = result.replace(match,transformToString(value))
i+=1 i+=1
}else{ }else{
break break

View File

@ -16,12 +16,12 @@ const scope1 ={
"*":{ "*":{
$types:{ $types:{
Date:(v)=>dayjs(v).format('YYYY/MM/DD'), Date:(v)=>dayjs(v).format('YYYY/MM/DD'),
Boolean:(v)=>v?"True":"False", Boolean:(v)=>v?"True":"False",
}, },
sum:(v,n=1)=>v+n,
double:(v)=>v*2,
upper:(v)=>v.toUpperCase(), upper:(v)=>v.toUpperCase(),
lower:(v)=>v.toLowerCase(), lower:(v)=>v.toLowerCase()
padStart:(v,len,pad)=>v.padStart(len,pad),
padStart:(v,len,pad)=>v.padStart(len,pad),
}, },
cn:{ cn:{
$types:{ $types:{
@ -105,7 +105,18 @@ test("替换翻译内容的位置插值变量",done=>{
}) })
test("替换翻译内容的命名插值变量",done=>{ test("替换翻译内容的命名插值变量",done=>{
expect(replaceVars("{a}{b}{c}",{a:1,b:2,c:3})).toBe("123"); expect(replaceVars("{a}{b}{c}",{a:11,b:22,c:33})).toBe("112233");
expect(replaceVars("{a}{b}{c}{a}{b}{c}",{a:1,b:"2",c:3})).toBe("123123"); expect(replaceVars("{a}{b}{c}{a}{b}{c}",{a:1,b:"2",c:3})).toBe("123123");
done() done()
})
test("命名插值变量使用格式化器",done=>{
// 提供无效的格式化器,直接忽略
expect(replaceVars("{a|x}{b|x|y}{c|}",{a:1,b:2,c:3})).toBe("123");
expect(replaceVars("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126");
// 默认的字符串格式化器,不需要定义使用字符串方法
expect(replaceVars("{a|x}{b|x|y}{c|double}",{a:1,b:2,c:3})).toBe("126");
expect(replaceVars("{a|padStart(10)}",{a:"123"})).toBe(" 123");
expect(replaceVars("{a|padStart(10)|trim}",{a:"123"})).toBe("123");
done()
}) })