如何检查字符串是否有效以及javascript中是否有有效的嵌套括号



这是字符串。我需要验证这个字符串的格式是否正确,并创建一个JSON。函数可以是加法、乘法、OR、AND等。并且可以有n个参数。

有效字符串

'AND(OR(abc,bcd,amd),SUM(efg,hig,4gm,4uf,hht),lmb)';

无效字符串(不包括)

'AND(OR(abc,bcd),SUM(efg,,lmb)';
'AND(OR(abc,),SUM(),lmb)';
'AND(OR(abc,bcd),SUM(asd,s)ig,lmb)';

预期的JSON

{
value: 'AND',
inputs: [
{
value: 'AND',
inputs: [
{value: abc},
{value: bcd}
]
},
{
value: 'AND',
inputs: [
{value: efg},
{value: hig}
]
},
{
value: lmb
}
]
}

我尝试过用字符分隔,但无法验证嵌套的字符串。

[...stringData].forEach((char) => {
if (char === '(' || char === ',' || char === ')') {
let obj = {
value: splitString,
type: standardFunctions[splitString] ? 'function' : 'param',
};
result.push(obj);
splitString = '';
} else {
splitString += char;
}
});

好吧,我想我已经解决了。

这里有一个围绕tokenStream构建的不错的递归解决方案,它使用正则表达式对字符串进行标记化和迭代。

parseExpr通过以下方式解析表达式:

  • 正在分析标识符令牌(名称)
  • 如果下一个字符是(,则通过调用自身(用逗号分隔)解析更多表达式,最后是)

如果解析表达式失败,则返回null,在这种情况下parse将抛出。

function parseExpr(tokenStream){
const id = parseID(tokenStream)
if(!id)
return null
const isFn = parseDelim(tokenStream, '(')
if(isFn){
const args = []
while(!parseDelim(tokenStream, ')')){
if(args.length > 0){
if(!parseDelim(tokenStream, ','))
return null
}
const expr = parseExpr(tokenStream)
if(!expr)
return null
args.push(expr)
}
return {
value: id,
inputs: args
}
}else{
return {
value: id
}
}
}
function parseID(tokenStream){
if(tokenStream.ended)
return null
const [, id, delim] = tokenStream.next
if(id === null)
return null

advanceTokenStream(tokenStream)
return id
}
function parseDelim(tokenStream, target){
if(tokenStream.ended)
return null
const [, id, delim] = tokenStream.next
if(delim === null || delim !== target)
return null

advanceTokenStream(tokenStream)
return delim
}
function advanceTokenStream(tokenStream){
const {done, value} = tokenStream.iter.next()
tokenStream.ended = done 
tokenStream.next = value
}
function parse(str){
if(!/^(?:[a-zA-Z0-9]+|[(),])*$/.test(str))
throw new Error('Tokenization failed')

const tokenStream = {
iter: str.matchAll(/(?:([a-zA-Z0-9]+)|([(),]))/gy)
}
advanceTokenStream(tokenStream)
const res = parseExpr(tokenStream)
if(res === null)
throw new Error('Parsing failed')
if(!tokenStream.ended)
throw new Error('Input has stuff after the expression')
return res
}
console.log(parse('AND(AND(abc,bcd),AND(efg,hig),lmb)'))
console.log(parse('AND(OR(abc,bcd,amd),SUM(efg,hig,4gm,4uf,hht),lmb)'))
console.log(parse('AND(AND(abc,bcd),AND(efg,h)ig,lmb)'))

您可以使用regex来验证它,也可以使用另一个regex来标记它。

然后用递归函数创建层次结构。

这可能需要更多的保护措施来防止潜在的错误,但这是朝着可能的方向迈出的一步。

const validInput = 'AND(AND(abc,bcd),AND(efg,hig),lmb)';
const invalidInput = 'AND(AND(abc,bcd),AND(efg,h)ig,lmb)';
const validator = /^([a-zA-Z]+([^)]+),|[a-z]|,)+$/;
const functionSplit = /^([a-zA-Z]+)(()(.*)())$/;
const tokenizer = /([a-zA-Z]+([a-z,]+)|[a-z]+)+/g;
function tokenize(string) {
try {
return recurse(string);
} catch {
return null;
}
function recurse(string) {
const funcTokens = string.match(functionSplit)
if (funcTokens) {
const [input, func, brace, inner] = funcTokens
return {
value: func,
inputs: recurse(inner),
};
} else {
if (!validator.test(string)) throw new Error('');
const tokens = string.match(tokenizer);
return tokens.length > 1 ? tokens.map(recurse) : {value: tokens[0]};
}
}
}
console.log('Invalid: ', tokenize(invalidInput));
console.log('Valid:', tokenize(validInput));

相关内容

最新更新