Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

正则表达式模版字符串 #48

Open
Sunny-117 opened this issue Nov 3, 2022 · 7 comments
Open

正则表达式模版字符串 #48

Sunny-117 opened this issue Nov 3, 2022 · 7 comments

Comments

@Sunny-117
Copy link
Owner

String.prototype.render = function (data) {
    return this.replace(/{{[.\s\S]*?}}/g, match => {
        if ((match = match.substring(2, match.length - 2).trim()) == "") {
            return "";
        } else if (match.startsWith("#")) {
            return eval(match.substr(1, match.length - 1));
        } else {
            return data[match] ? data[match] : "";
        }
    })
}


const data = {
    name: "小明",
    age: 16,
    school: "第三中学",
    classroom: "教室2"
}


console.log(
    "{{ name }} 今年 {{ age }} 岁,就读于 {{ school }} 今天在 {{ classroom }} 上课,{{ name }} {{ #data.age >= 18 ? '成年了' : '未成年' }}".render(data)
);
// 小明 今年 16 岁,就读于 第三中学 今天在 教室2 上课,小明 未成年

console.log(
    `{{name}}说了句{{#
        if (data.age >= 18) {
            "我已经成年了!"
        } else {
            "我还没有成年!"
        }
    }}`.render(data)
);
// 小明说了句我还没有成年!
@pengzhanbo
Copy link

pengzhanbo commented Dec 30, 2022

function createTemplate(template = '', option = {}) {
  const { dynamic = ['{{', '}}'], statement = '#' } = option
  const RE_CONTENT = '[.\\s\\S]*'
  const RE_DYNAMIC = new RegExp(
    `(${RE_CONTENT}?)${dynamic[0]}(${RE_CONTENT}?)${dynamic[1]}(${RE_CONTENT})`
  )
  const tokens = []
  const createTokens = (tpl) => {
    const match = tpl.match(RE_DYNAMIC)
    if (match) {
      // ['', text, dynamic, nexTemplate] = match
      match[1] && tokens.push({
        type: 'text',
        content: match[1],
      })
      const dynamicMatch = match[2].trim()
      dynamicMatch && tokens.push({
        type: dynamicMatch.startsWith(statement) ? 'statement' : 'dynamic',
        content: dynamicMatch,
      });
      match[3] && createTokens(match[3])
    } else {
      tokens.push({
        type: 'text',
        content: tpl,
      })
    }
  }

  createTokens(template)

  return function format(data) {
    return tokens.map(({ type, content }) => {
      switch (type) {
        case 'text':
          return content
        case 'dynamic':
          return data[content]
        case 'statement':
          const fn = new Function(...Object.keys(data), content.slice(1))
          return fn(...Object.values(data))
      }
    }).join('')
  }
}

const template = createTemplate(`
  名字: {{ name }}
  {{}}
  年龄: {{ age }}
  {{#
    if (age > 18) {
      return '成年人' 
    } else { 
      return '未成年人' 
    }
  }}
`)

console.log(template({ name: "张三", age: 14 }))
console.log(template({ name: "李四", age: 19 }))

@jlx2002
Copy link
Contributor

jlx2002 commented Jan 15, 2023

补一个双指针的写法,效率可能高一点。
好奇题目的模板字符串的含义,不应该是 es6 标准的${}这种字符串吗?

const data = {
  name: "小明",
  age: 16,
  school: "第三中学",
  classroom: "教室2",
};
// 解构取值
let { name, age, school, classroom } = data;

/**
 * @description: 双指针匹配 模板字符串,发现${}
 * @param {*} s
 * @return {*}
 * @author: jlx
 */
function matchStrV2(s) {
  let res = "";
  for (let i = 0; i < s.length - 1; i++) {
    let j = i + 2;
    if (s[i] == "$" && s[i + 1] == "{") {
      // 直到 右侧括号匹配成功
      while (j < s.length && s[j] != "}") j++;
      // 说明匹配成功
      if (s[j] == "}") {
        res += eval(s.substring(i + 2, j));
      }
      i = j + 1;
    } else {
      res += s[i];
    }
  }
  return res;
}

let cases =
  "${ name } 今年 ${ age } 岁,就读于 ${ school } 今天在 ${ classroom } 上课,${ name } ${ data.age >= 18 ? '成年了' : '未成年' }";

console.log(matchStrV2(cases));
// 小明今年 16岁,就读于 第三中学今天在 教室2上课,小明未成年

// 如果是es6标准的模板字符串``,第二个case好像是非法的

@whale2002
Copy link

String.prototype.render = function (data) {
    return this.replace(/{{[.\s\S]*?}}/g, match => {
        if ((match = match.substring(2, match.length - 2).trim()) == "") {
            return "";
        } else if (match.startsWith("#")) {
            return eval(match.substr(1, match.length - 1));
        } else {
            return data[match] ? data[match] : "";
        }
    })
}


const data = {
    name: "小明",
    age: 16,
    school: "第三中学",
    classroom: "教室2"
}


console.log(
    "{{ name }} 今年 {{ age }} 岁,就读于 {{ school }} 今天在 {{ classroom }} 上课,{{ name }} {{ #data.age >= 18 ? '成年了' : '未成年' }}".render(data)
);
// 小明 今年 16 岁,就读于 第三中学 今天在 教室2 上课,小明 未成年

console.log(
    `{{name}}说了句{{#
        if (data.age >= 18) {
            "我已经成年了!"
        } else {
            "我还没有成年!"
        }
    }}`.render(data)
);
// 小明说了句我还没有成年!

面试会考正则吗,完全不会

@kangkang123269
Copy link

function renderTemplate(template, data) {
  const regex = /{{(.*?)}}/g;
  return template.replace(regex, (match, key) => {
    if (key.startsWith("#")) {
      return eval(key.substr(1));
    } else {
      return data[key.trim()] || "";
    }
  });
}

@xun-zi
Copy link

xun-zi commented Mar 13, 2023

/**
     *遇到#表示是表达式
     *遇到字符表示变量 
     */
    String.prototype.render = function (data) {
        return this.replace(/{{[\s\S]*?}}/g, match => {
            match = match.slice(2, match.length - 2).trim();
            // console.log(match)
            if (match == "") {
                return;
            } else if (match[0] == '#') {
                return eval(match.slice(1));
            } else {
                return data[match] || '';
            }
        })
    }
    const data = {
        name: "小明",
        age: 16,
        school: "第三中学",
        classroom: "教室2"
    }


    console.log(
        "{{ name }} 今年 {{ age }} 岁,就读于 {{ school }} 今天在 {{ classroom }} 上课,{{ name }} {{ #data.age >= 18 ? '成年了' : '未成年' }}".render(data)
    );
    // 小明 今年 16 岁,就读于 第三中学 今天在 教室2 上课,小明 未成年

    console.log(
        `{{name}}说了句{{#
        if (data.age >= 18) {
            "我已经成年了!"
        } else {
            "我还没有成年!"
        }
    }}`.render(data)
    );
        // 小明说了句我还没有成年!

@luckymore
Copy link

索性把正则写完整一些,少一些字符串操作吧

function resolveStr(tpl, model) {
  const reg = /{{\s*(.+?)\s*}}/g
  return tpl.replace(reg, (str, key) => {
    if (key.startsWith('#')) {
      key = key.slice(1)
      return eval(key)
    }
    console.log(str, key)
    return eval(`model.${key}`)
  })
}

@gswysy
Copy link

gswysy commented Apr 5, 2024

String.prototype.render = function (data) {
    return this.replace(/{{\s*([\S\s]*?)\s*}}/g, (match, p1) => {
        if (p1 && p1[0] === '#') return eval(p1.slice(1))
        else return data[p1] || ''
    })
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants