我有一个类似于这个的JSON字符串:
{
"Version": "XXX",
"Statements": [
{...},
{...},
{...}
]
}
Run Code Online (Sandbox Code Playgroud)
如何找出XX在JSON字符串的字符中定义Statements属性中的哪个对象?(考虑到那些对象可以任意深度嵌套).
例如,如果我有一个字符串
{"Version":"XXX","Statements":[{"a":1},{"b":2},{"b":3}]}
--------------------------------------------------------
123456789 123456789 123456789 123456789 123456789 123456
Run Code Online (Sandbox Code Playgroud)
然后位置上的字符36将对应于第一个语句对象,而位置上的字符52将对应于第三个语句对象.
这是一些不需要外部库的脏解决方案:
const data = '{"Version":"XXX","Statements":[{"a":1},{"b":2},{"b":3}],"some":0}';
const getValuesPositionInArray = arrayKey => data => {
const arrayNameSeparator = `"${arrayKey}":`;
const targetArrayIndexOf = data.indexOf(arrayNameSeparator) + arrayNameSeparator.length;
const arrayStringWithRest = data.slice(targetArrayIndexOf, data.length);
const { result } = arrayStringWithRest.split('').reduce(
(acc, char, idx, array) => {
if (acc.finished) return acc;
if (!acc.processingKey && char === '[') acc.nesting += 1;
if (!acc.processingKey && char === ']') acc.nesting -= 1;
const shouldFinish = acc.nesting === 0;
const charIsDblQuote = char === '"';
const charBefore = array[idx - 1];
const charAfter = array[idx + 1];
acc.position += 1;
acc.finished = shouldFinish;
if (acc.processingKey && !charIsDblQuote) acc.processedKey += char;
if (charIsDblQuote) acc.processingKey = !acc.processingKey;
if (charIsDblQuote && !acc.processingKey && charAfter === ':') {
acc.result[acc.processedKey] = acc.position;
acc.processedKey = '';
}
return acc;
},
{
finished: false,
processingKey: false,
processedKey: '',
nesting: 0,
position: targetArrayIndexOf + 1,
result: {}
}
)
return result;
}
const result = getValuesPositionInArray('Statements')(data);
console.log(result)Run Code Online (Sandbox Code Playgroud)
但是,如果目标对象包含字符串值,则此片段将中断.
编辑
以下是更新的片段,其中包含字符串值修复和解析值:
const data = '{"Version":"XXX","Statements":[{"aa":"some"},{"b":"ano:,{ther}"},{"bb":3}],"some":0}';
const getValuesPositionInArray = arrayKey => data => {
const arrayNameSeparator = `"${arrayKey}":`;
const targetArrayIndexOf = data.indexOf(arrayNameSeparator) + arrayNameSeparator.length;
const arrayStringWithRest = data.slice(targetArrayIndexOf, data.length);
const charsAfterValue = ['}', ','];
const charsBeforeKey = ['{', ','];
const { result } = arrayStringWithRest.split('').reduce(
(acc, char, idx, array) => {
if (acc.finished) return acc;
if (!acc.processingKey && !acc.processingValue && char === '[') acc.nesting += 1;
if (!acc.processingKey && !acc.processingValue && char === ']') acc.nesting -= 1;
const shouldFinish = acc.nesting === 0;
const charIsDblQuote = char === '"';
const charBefore = array[idx - 1];
const charAfter = array[idx + 1];
const keyProcessingStarted = (
charIsDblQuote &&
!acc.processingKey &&
!acc.processingValue &&
charsBeforeKey.includes(charBefore)
);
const keyProcessingFinished = (
charAfter === ':' &&
charIsDblQuote &&
acc.processingKey
);
const valueProcessingStarted = (
char === ':' &&
!acc.processingKey &&
!acc.processingValue
);
const valueProcessingFinished = (
(acc.lastProcessedValueType === String
? charIsDblQuote
: true
) &&
acc.processingValue &&
charsAfterValue.includes(charAfter)
);
acc.position += 1;
acc.finished = shouldFinish;
if (acc.processingKey && !charIsDblQuote) acc.processedKey += char;
if (acc.processingValue && !charIsDblQuote) acc.processedValue += char;
if (keyProcessingStarted) {
acc.processingKey = true;
} else if (keyProcessingFinished) {
acc.processingKey = false;
acc.result[acc.processedKey] = { position: acc.position };
acc.lastProcessedKey = acc.processedKey;
acc.processedKey = '';
}
if (valueProcessingStarted) {
acc.processingValue = true;
acc.lastProcessedValueType = charAfter === '"' ? String : Number;
} else if (valueProcessingFinished) {
acc.processingValue = false;
acc.result[acc.lastProcessedKey].value = (
acc.lastProcessedValueType(acc.processedValue)
);
acc.processedValue = '';
acc.lastProcessedKey = '';
acc.lastProcessedValueType = (v) => v;
}
return acc;
},
{
finished: false,
processingKey: false,
processingValue: false,
processedKey: '',
processedValue: '',
lastProcessedKey: '',
lastProcessedValueType: (v) => v,
nesting: 0,
position: targetArrayIndexOf + 1,
result: {}
}
)
return result;
}
const result = getValuesPositionInArray('Statements')(data);
console.log(result)Run Code Online (Sandbox Code Playgroud)
要在json字符串中找到某些内容的位置,如果要构建自己的算法,需要考虑几个因素,一个问题是几个字符串可能导致相同的对象字面值,也就是属性的顺序.对象不保证,那么相同的字符串可能会导致属性中的顺序不同.我们知道字符串中的所有.方法{,但[可能意味着[或{.因此,为了找到1例如的位置,我们应该删除原始字符串中的空格并执行递归循环并再次构建json并找到匹配项.这里只是一个找到1的位置的例子:
var json = '{"Version":"XXX","Statements":[{"a":1},{"b":2},{"b":3}]}';
var obj = JSON.parse(json)
var str2 = ""
for(p in obj){
str2 += "{";
str2 += p+":";
if(p == "Statements"){
str2 += ":["
obj[p].forEach(o=>{
for(p2 in o){
if(p2 == "a"){
str2 += '{"a":'
}
}
})
}else{
str2 +='"'+obj[p]+'",'
}
}
console.log(str2)
console.log(str2.length+1)Run Code Online (Sandbox Code Playgroud)
这个例子不准确,它只是向您展示一种可能的方法.在真实和通用的解决方案中,您应该考虑数百种事情.
在做了大量研究之后,我认为我没有使用esprima包编写自己的解析器.因为esprima不是特定于JSON(而是JavaScript),所以我必须将我的JSON字符串包装到括号中.
树中的每个元素都包含一个loc属性,其范围与原始JSON字符串中的位置相匹配.
var esprima = require("esprima");
var JSONPath = require('JSONPath');
function getStatementIndex(str, line, column) {
var tree = esprima.parseScript(str, {loc:true});
var query = "$.body[0].expression.properties[?(@.key.value=='Statement')].value.elements[*].loc";
var locations = JSONPath({json: tree, path: query});
console.log(locations);
for(var i = 0; i < locations.length; i++) {
var loc = locations[i];
var contains = false;
if (loc.start.line < line && loc.end.line > line) {
continue;
}
// If a single line and in between
if (loc.start.line == loc.end.line && loc.start.line == line) {
if (loc.start.column <= column && loc.end.column >= column) {
contains = true;
}
// If on the beginning line
} else if (loc.start.line == line && loc.start.column <= column) {
contains = true;
// If on the end line
} else if (loc.end.line == line && loc.end.column >= column) {
contains = true;
// If in between
} else if (loc.start.line < line && loc.end.line > line) {
contains = true;
}
if (contains)
return i;
}
return -1;
}
var result = getStatementIndex(str, 81, 7);Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
876 次 |
| 最近记录: |