gpt4 book ai didi

javascript - 将数字从字符串替换为对象

转载 作者:行者123 更新时间:2023-12-03 04:05:10 25 4
gpt4 key购买 nike

我有两个变量

var sequence = '(1 AND 2) OR (2 AND 3)'
var filters =[{
"name": "title",
"opr": "=",
"value": "My Post",
"sid": "1"
},
{
"name": "content",
"opr": "like",
"value": "Hello",
"sid": "2"
},
{
"name": "id",
"opr": "gt",
"value": "100",
"sid": "3"
}
]

现在我正在寻找替换序列并将其转换为如下格式

 var output = {
"OR": [{
"AND": [{
"title": "My Post"
},
{
"content": {
"like": "Hello"
}
}
]
},
{
"AND": [{
"content": {
"like": "Hello"
}
},
{
"id": {
"gt": "1000"
}
}
]
}
]
}
}

对于序列字符串,每个数字代表对象数组中的 sid对于对象数组中的 opr ,如果 opr 等于 "=" ,它应该创建简单的键值对对象,例如

{"title": "My Post"}

对于其他运算符,它应该创建类似

{"content": {"like": "Hello"}}

最佳答案

您想要创建一个解析器。

您的用例可能会有所不同,并会改变您想要做出的权衡,但这里有一个简单的实现,可以完成您上面概述的内容。

const SEQUENCE = "(1 AND 2) OR (2 AND 3)";

const FILTERS = [{
name: "title",
opr: "=",
value: "My Post",
sid: "1"
},
{
name: "content",
opr: "like",
value: "Hello",
sid: "2"
},
{
name: "id",
opr: "gt",
value: "1000",
sid: "3"
}
];

const result = compiler(SEQUENCE, FILTERS);

console.log(result);

function compiler(sequence, filters) {
let tokens = _tokenizer(sequence);
let ast = _parser(tokens);
let newAst = _transformer(ast);
let output = _generator(newAst, filters, {});
return output;
}

//////////////////////////
function _tokenizer(input) {
let current = 0;
let tokens = [];
let expr = /^[(].*[)]$/;
let needsParens;
let parenCounter;

[].forEach.call(input, function(char, index) {
if (char === '(') parenCounter = (parenCounter == null) ? 1 : parenCounter + 1;
if (char === ')') --parenCounter;
if (parenCounter === 0 && index != input.length - 1) needsParens = true;
});

if (!expr.test(input) || needsParens) input = "(" + input + ")";

while (current < input.length) {
let char = input[current];

if (char === '(') {
tokens.push({
type: 'paren',
value: '(',
});
current++;
continue;
}

if (char === ')') {
tokens.push({
type: 'paren',
value: ')',
});
current++;
continue;
}

let WHITESPACE = /\s/;
if (WHITESPACE.test(char)) {
current++;
continue;
}

let NUMBERS = /[0-9]/;
if (NUMBERS.test(char)) {
let value = '';

while (NUMBERS.test(char)) {
value += char;
char = input[++current];
}

tokens.push({
type: 'number',
value
});

continue;
}

let LETTERS = /[A-Z]/i;
if (LETTERS.test(char)) {
let value = '';

while (LETTERS.test(char)) {
value += char;
char = input[++current];
}

tokens.push({
type: 'name',
value
});

continue;
}

throw new TypeError('Unknown token: ' + char);
}

return tokens;
}
//////////////////////////

//////////////////////////
function _parser(tokens) {
let current = 0;

function walk() {
let token = tokens[current];

if (token.type === 'number') {
current++;

return {
type: 'NumberLiteral',
value: token.value,
};
}

if (token.type === 'name') {
current++;

return {
type: 'NameLiteral',
value: token.value,
};
}

if (token.type === 'paren' && token.value === '(') {
token = tokens[++current];

let node = {
type: 'Expression',
params: [],
};

while ((token.type !== 'paren') || (token.type === 'paren' && token.value !== ')')) {
node.params.push(walk());
token = tokens[current];
}

current++;

return node;
}

throw new TypeError(token.type);
}

let ast = {
type: 'Program',
body: [],
};

while (current < tokens.length) {
ast.body.push(walk());
}

return ast;
}
//////////////////////////

//////////////////////////
function _traverser(ast, visitor) {

function _traverseArray(array, parent) {
array.forEach(child => {
_traverseNode(child, parent);
});
}

function _traverseNode(node, parent) {
let methods = visitor[node.type];

if (methods && methods.enter) methods.enter(node, parent);

switch (node.type) {
case 'Program':
_traverseArray(node.body, node);
break;

case 'Expression':
_traverseArray(node.params, node);
break;

case 'NumberLiteral':
case 'NameLiteral':
break;

default:
throw new TypeError(node.type);
}

if (methods && methods.exit) methods.exit(node, parent);
}

_traverseNode(ast, null);
}
//////////////////////////

//////////////////////////
function _transformer(ast) {

let newAst = {
type: 'Program',
body: [],
};

ast._context = newAst.body;

_traverser(ast, {
NumberLiteral: {
enter(node, parent) {
parent._context.push({
type: 'NumberLiteral',
value: node.value,
});
},
},

NameLiteral: {
enter(node, parent) {
parent._expression.bool = node.value;
},
},

Expression: {
enter(node, parent) {
let expression = {
type: 'Expression',
arguments: [],
};

node._expression = expression;
node._context = expression.arguments;

parent._context.push(expression);
},
}
});

return newAst;
}
//////////////////////////

//////////////////////////
function _generator(node, filters, map) {
if (filters) filters.forEach(filter => map[filter.sid] = filter);
switch (node.type) {

case 'Program':
return JSON.parse(_generator(node.body[0], null, map));

case 'Expression':
return '{"' + node.bool + '":[' + node.arguments.map(arg => _generator(arg, null, map)) + ']}';

case 'NumberLiteral':
let filter = map[node.value];
if (filter.opr === '=') return '{"' + filter.name + '":"' + filter.value + '"}';
return '{"' + filter.name + '":{"' + filter.opr + '":"' + filter.value + '"}}';

default:
throw new TypeError(node.type);
}
}
//////////////////////////

这是基于 James Kyle's Super Tiny Compiler .

为了简洁起见,我删除了所有评论,并进行了大量编辑以满足您的要求。如果您想了解它是如何工作的或者想在将来有机会调试或扩展它,您绝对应该查看该存储库。

从高层来看,这就是正在发生的事情。

  1. 分词器分隔特殊字符、空格和值。
  2. 解析器获取标记并生成 abstract syntax tree (AST)。
  3. 转换器会抓取 AST 并根据我们的用例对其进行修改。
  4. 生成器使用 AST 和过滤器数据编译所需的输入。

再一次,不能推荐James Kyle's Super Tiny Compiler够了。

关于javascript - 将数字从字符串替换为对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44592254/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com