需求背景
要做一个计算公式输入框(可下拉出数据可自己输入符号),输入对应的汉字模糊搜索出对应的数据,可输入计算符号,可选计算项。显示的是汉字的公式但是最后传给后端的是映射之后的code值公式,而且数据源可能有重复
实现
- 下拉框
- 输入符号
- 解决数据源重复
代码
/**
* 计算公式标签
* 下拉选择
* 仿excel 计算公式功能
*/
import React, {useEffect, useState} from "react"
import {Mentions, Input } from 'antd';
import { AutoComplete } from 'antd';
const { TextArea } = Input;
const { Option } = Mentions ;
let data = [{value: 'code1', text: '代码'},
{value: 'code2', text: '李三代码'},
{value: 'code3', text: '王五代码1'},
{value: 'code4', text: '赵六代码2'},
{value: 'code5', text: '孙七代码3'},
{value: 'code6', text: '李八代码4'},
{value: 'code7', text: '孙九代码5'},
{value: 'code7_1', text: '孙九代码5 '}
]
const coins = ["+", "-", "*", "/", "(", ")", "="]
export default () => {
let [dataSource, setDataSource] = useState([]);
const [open, setOpen] = useState(false);
useEffect(() => {
document.getElementById('auto_inp').addEventListener('keyup', onChnage)
return () => {
document.getElementById('auto_inp').removeEventListener('keyup', onChnage)
}
}, [])
function onSelect1(value) {
setOpen(false)
}
function handleSearch(value) {
if (!(/[a-zA-Z]/i.test(value))) {
setOpen(true)
const end_point = document.getElementById('auto_inp').selectionEnd; //结束点
const par_val = value.substring(0, end_point);
let start_i = 0; //开始点
for (let i = par_val.length - 1; i > 0; i--) {
if (coins.indexOf(par_val[i]) > -1) {
start_i = i;
break;
}
}
let new_arr = [];
data.map(t=>{
if (t.text.indexOf(value.substring(start_i, end_point).replace(/[^\u4e00-\u9fa5]/gi, "")) > -1) {
new_arr.push(value.substring(0, start_i) + (coins.indexOf(par_val[start_i]) > -1 ? par_val[start_i] : '') + t.text + value.substring(end_point).trim());
}
})
setDataSource(new_arr);
} else {
setOpen(false)
setDataSource([]);
}
};
function onChnage(e) {
if (coins.indexOf(e.key) > -1) {
setOpen(false)
}
}
function onKeyDown(e) {
const keys = [65, 67, 83, 86, 13, 32]
if(keys.indexOf(e.keyCode) > -1){
e.preventDefault();
return;
}
}
return (
<>
<AutoComplete
dataSource={dataSource}
backfill = {true}
style={{ width: 575 }}
onSelect={onSelect1}
onSearch={handleSearch}
open = {open}
>
<TextArea
id="auto_inp"
placeholder="请选择需要内容"
className="custom"
onKeyDown={(e)=>onKeyDown(e)}
style={{ height: 50, whiteApace: 'text-overflow' }}
/>
</AutoComplete>
</>
)
}
代码优化
中文计算公式与英文计算公式互相转换。
- 中文计算转英文计算公式并根据映射关系计算出结果
思路:先确定计算符号,使用一个开始指针和当前的i位置,遍历就好了,时间复杂度为O(N)。然后使用eval()计算公式,就计算出结果了
// 中文和空格正则表达式
let regex = /[\u4e00-\u9fa5]/;
let compute_str = ""; //计算公式映射
let compute_codes = "";
for (let i = 0; i < arr.length; i ++) {
if (!regex.test(arr[i])) {
if (i > start_i) {
let new_obj = source.find(t=>t.text === arr.substring(start_i, i))
compute_str += billing_basis_map[new_obj?.value];
compute_codes += new_obj?.value;
}
start_i = i+1;
compute_str += arr[i];
compute_codes += arr[i];
} else if (i == arr.length - 1) {
let new_obj = source.find(t=>t.text === arr.substring(start_i == 0 ? 0 :start_i, arr.length))
compute_str += billing_basis_map[new_obj?.value];
compute_codes += new_obj?.value;
}
}
this.setState({compute_codes})
try {
event_money = eval(compute_str)
} catch (error) {
message.error('请按要求输入完整公式')
}
- 英文转中文实现思路一样