javascript - 解析半结构化值

标签 javascript json parsing

这是我的第一个问题。我试图找到答案,但老实说,我无法弄清楚我应该使用哪些术语,如果之前有人问过,我很抱歉。

这里是: 我在 .txt 文件中有数千条记录,格式如下:

(1, 3, 2, 1, 'John (Finances)'),
(2, 7, 2, 1, 'Mary Jane'),
(3, 7, 3, 2, 'Gerald (Janitor), Broflowski'),

...等等。第一个值是 PK,其他 3 个是外键,第 5 个是字符串。

我需要在 Javascript 中将它们解析为 JSON(或其他东西),但我遇到了麻烦,因为有些字符串有括号+逗号(在第 3 条记录上,例如“Janitor”),所以我不能使用子字符串。 .. 可能会 trim 正确的部分,但我想知道是否有一些更聪明的方法来解析它。

非常感谢任何帮助。

谢谢!

最佳答案

您不能(阅读可能不应该)为此使用正则表达式。如果括号中包含另一对或一对不匹配怎么办?

好消息是您可以轻松地为此构造一个分词器/解析器。 这个想法是跟踪您当前的状态并采取相应的行动。

这是我刚刚在此处编写的解析器的草图,目的是向您展示总体思路。如果您对此有任何概念性问题,请告诉我。

有效 demo here但我恳求你在理解和修补它之前不要在生产中使用它。


工作原理

那么,我们如何构建解析器:

var State = { // remember which state the parser is at.
     BeforeRecord:0, // at the (
     DuringInts:1, // at one of the integers
     DuringString:2, // reading the name string
     AfterRecord:3 // after the )
};

我们需要跟踪输出和当前工作对象,因为我们将一次解析这些。

var records = []; // to contain the results
var state = State.BeforeRecord;

现在,我们迭代字符串,继续前进并读取下一个字符

for(var i = 0;i < input.length; i++){
    if(state === State.BeforeRecord){
        // handle logic when in (
    }
    ...
    if(state === State.AfterRecord){
        // handle that state
    }
}

现在,剩下的就是在每个状态下将它消耗到对象中:

  • 如果它在 ( 我们开始解析并跳过任何空格
  • 读取所有整数并放弃 ,
  • 在四个整数之后,从'读取字符串到下一个'直到结束
  • 在字符串之后,读取到),存储对象,再次开始循环。

实现起来也不是很困难。


解析器

var State = { // keep track of the state
     BeforeRecord:0,
     DuringInts:1,
     DuringString:2,
     AfterRecord:3
};
var records = []; // to contain the results
var state = State.BeforeRecord;
var input = " (1, 3, 2, 1, 'John (Finances)'), (2, 7, 2, 1, 'Mary Jane'), (3, 7, 3, 2, 'Gerald (Janitor), Broflowski')," // sample input

var workingRecord = {}; // what we're reading into.

for(var i = 0;i < input.length; i++){
    var token = input[i]; // read the current input
    if(state === State.BeforeRecord){ // before reading a record
        if(token === ' ') continue; // ignore whitespaces between records
        if(token === '('){ state = State.DuringInts; continue; }
        throw new Error("Expected ( before new record");
    }
    if(state === State.DuringInts){
        if(token === ' ') continue; // ignore whitespace
        for(var j = 0; j < 4; j++){
            if(token === ' ') {token = input[++i]; j--; continue;} // ignore whitespace 
             var curNum = '';
             while(token != ","){
                  if(!/[0-9]/.test(token)) throw new Error("Expected number, got " + token);
                  curNum += token;
                  token = input[++i]; // get the next token
             }
             workingRecord[j] = Number(curNum); // set the data on the record
             token = input[++i]; // remove the comma
        }
        state = State.DuringString;
        continue; // progress the loop
    }
    if(state === State.DuringString){
         if(token === ' ') continue; // skip whitespace
         if(token === "'"){
             var str = "";
             token = input[++i];
             var lenGuard = 1000;
             while(token !== "'"){
                 str+=token;
                 if(lenGuard-- === 0) throw new Error("Error, string length bounded by 1000");
                 token = input[++i];
             }
             workingRecord.str = str;
             token = input[++i]; // remove )
             state = State.AfterRecord;
             continue;
         }
    }
    if(state === State.AfterRecord){
        if(token === ' ') continue; // ignore whitespace
        if(token === ',') { // got the "," between records
            state = State.BeforeRecord;
            records.push(workingRecord);
            workingRecord = {}; // new record;
            continue;
        }
        throw new Error("Invalid token found " + token);
    }
}
console.log(records); // logs [Object, Object, Object]
                      // each object has four numbers and a string, for example
                      // records[0][0] is 1, records[0][1] is 3 and so on,
                      // records[0].str is "John (Finances)"

关于javascript - 解析半结构化值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24252352/

相关文章:

c++ - 用名称标记 std::function?

javascript - Ajax Autocomplete 用相同的值填充两个输入字段,尽管我已经用不同的逻辑分别实现了这两个功能

python - 如何使用 pymongo 将集合转储到 json 文件

python mailchimp api 2.0 json响应错误

python - BeautifulSoup 无法解析内容,因为页面加载速度太慢

python - Pyparsing - 从混合的 jascii/ascii 文本文件中解析 jascii 文本?

javascript - TamperMonkey - 不同子域上的脚本之间的消息

javascript - 我无法设法将此 JSON 数据放入 DataTables 中

javascript - tinyMCE 粘贴为单词

javascript - 只读取 JavaScript 中的第一个值