关于正则

和老it一起做的项目,第一期终于快要完成了,剩下两个比较麻烦的,其中之一是一个复杂的表单模块,用来记录被调查者的各类信息。

前两天老it循循善诱:“$140,要不要挑战下?”

我心想问题应该不大,就先接了,把需求整个弄清楚后,我日了。。。

简单来说:对方只给了一张人工输入的sheet表格,共350+个表单,表格中用文字列出每个表单的各种字段及显示隐藏条件,部分表单的值由前面表单的值通过某些公式计算。

而且某些行里对应的是若干个相关联的表单,比如下面的是在sheet中的一行:

Actual Field Name  Type
-----------------------------
Address:          
Address Line 1     Textfield
Address Line 2     Textfield
City               Textfield
State              Dropdown
Zip code           Number
-----------------------------

所以我们采取的方式是:

1.先将sheet表格转一个JsonA

2.从JsonA生成一个 表单配置对象config,用来传给vue

3.表单中的各种dropdown、checkboxes选项来自另一个数据源,转为一个JsonB

4.将JsonB那些下拉菜单和选框通过匹配label配对到对应的表单配置项

5.生成的config中处理好每一个label的格式、要传到后台的name的格式

6.给那些有显示隐藏条件的表单的配置对象添加show函数来控制显示

7.完成后台的crud接口

这两天做也蛮痛苦,需求逐渐确认,各种小坑,单是排查都排查了7、8遍以上。但是多亏了正则表达式,情况没想象中那么恶心。以前我只是用正则来验证email、密码、身份证之类的,偶尔.replace(regxep,xx)来修葺文本,但这次真是帮了大忙。

1.分离JSON中复合的表单

第一个问题比较简单,sheet转json后要把每个表单独立出来,如遍历中的某个对象n:

{"Actual Field Name":"Address :\nAddress Line 1\nAddress Line 2\nCity\nState\nZip code","Visible/Hidden":"Visible","Type":"Textfield\nTextfield\nTextfield\nDropdown\nNumber","R/O":"Required","Format":"99999-9999(ZipCode)"}

像抽离出每个表单,可以像下面这样在for循环里:

let rawName = n["Actual Field Name"].split(/\n/).map(name=>name.trim());
let rawtype = n["Type"].split(/\n/).map(type=>type.trim());
let prefix = rawName[0].replace(/[:| ]/g,'');
let fields = rawName.slice(1).map((each,index)=>{
  {...n,"Actual Field Name":prefix+each,"Type":rawtype[index]}
})

然后通过Array.splice(index,1,fields)就可以完成第一次改造了。

2.标准化label和name

任何项目中,命名风格必须统一,由于label由特定的要求,所以和表单的name分别改造,name标准为驼峰写法,去除特殊字符:

function name2Standard(str){
  return str.split(/[^a-zA-Z0-9]+/).map(n=>n[0]&&(n[0].toUpperCase()+n.slice(1))).filter(n=>n!==undefined).join(' ').replace(/\s+/g,'').split('').map((n,i)=>i===0?n.toLowerCase():n).join('')
}

3.互相匹配

由于JsonB里的表单选项是"Actual Field Name":[]形式,所以可以在标准化"Actual Field Name"后,通过匹配Actual Field Name"来给表单配置填充对应的options。

function heading2Standard(str){
    let l = str.length;
    let ending = str[l-1];
   return  (str.slice(0,l-1).replace(/[[A-Z][a-z]|\d+]/g,function(old){return ' '+old})
   .replace(/[\_|:+]/g,'')
   .replace(/\s+/g,' ')
   .replace(/\/ /g,'/')
   .trim()+ending);
}

4.添加函数

很大的一个配置config,总不能一个个添加函数吧,这也太辛苦了。由于显示逻辑写在"Visible/Hidden"字段里,比如:

{"Visible/Hidden":"Hidden (DoesTheClientReportAPersonalHistoryOfEmotionalAbuse.Contains(\"reports having been emotionally abused in the past\")) or (DoesTheClientReportAPersonalHistoryOfPhysicalAbuse.Contains(\"reports having been physically abused in the past\")) or (DoesTheClientReportAPersonalHistoryOfSexualAbuse.Contains(\"reports having been sexually abused in the past\"))"}

我们可以通过正则来尽量匹配需要添加显示的表单:

const run = async function() {
    Object.keys(gs).forEach(name => {
        let rows = gs[name];
        rows.filter(r => /Contains/.test(r["Visible/Hidden"])).forEach(r => {
            let v = r["Visible/Hidden"];
            let pair = v.split(") or ");
            let groups = pair.map(p => {
                let str = p.match(/\"(.*?)\"/);
                let base = v.match(/[\b\.\()]([^\.]*?)\.Contains/);
                if (!str || !base) {
                    debugger;
                }
                return { str: str[1], base: base[1] };
            });
            let result = groups.map(e => `/${e.str}/.test(model["${e.base[0].toLowerCase()+e.base.slice(1)}"])`).join(" || ");
            var a = 1;
            result = `aaafunction(model){ return ${result}}aaa`;
            r["Visible/Hidden"] = result;
        });

        // is yes
        rows.filter(r => /is yes$/.test(r["Visible/Hidden"])).forEach(r => {
            let v = r["Visible/Hidden"];
            let base = v.match(/ (.*?) is yes/i);
            if (!base) {
                debugger;
            }
            base = base[1];
            let first = base[0].toLowerCase();
            let remain = base.slice(1);
            let result = `aaafunction(model){ return model["${first+remain}"]}aaa`;
            r["Visible/Hidden"] = result;
        });
    });

}

run();

将目前的config传进去后,函数会尽量查找需要添加显示/隐藏逻辑的表单对象,并将“Visible/Hidden”的字符串值改写为一个

`aaafunction(model){ return model["${first+remain}"]}aaa`

方便我们在编辑器上control+F去批量处理,将这个'Visible/Hidden'改为方法。这时候已经大大减少我们的工作量了。对于剩下的,只能我们自己去排查。

 

至于后台CRUD部分,传给mongoose的schema和typescript的Interface,直接从这个config配置中通过编辑器批量操作再移植就好了。这些工作量,不是开发,更多是编辑。

目前这个任务已经完成得差不多,过程坑很多,比如sheet中好些地方字母是拼错的,但我们又改不了那张sheet;有些选项的数据是缺失的,需要自己去查询拷贝;或者sheet中没有告知隐藏的表单中有些button点击后需要动态生成一组新表单。 但是有正则帮忙,大大降低了模式匹配和修正的工作量。

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值