使用javascript将服务器响应字符串转换为有效的JSON

时间:2017-10-25 06:42:27

标签: javascript json regex

我无法控制修改服务器端点以返回有效的JSON。

端点:http://newsrack.in/stories/servelots/iihs_feeds/16.json

样本回复数据:

    `var _nr_metadata = {
      site_base_url : "http://newsrack.in",
      issue_name    : "iihs_feeds",
      category_name : "Chikungunya",
      listing_url   : "/stories/servelots/iihs_feeds/16"
    }
    var _nr_stories = [
       {
    title  : "Delhi: Changing weather conditions cause 25 per cent rise in dengue cases",
    url    : "http://indiatoday.intoday.in/story/delhi-changing-weather-conditions-cause-rise-in-dengue-cases/1/1075570.html",
    source : "India Today| Must Read",
    date   : "26.10.2017",
    desc   : "<a href=\'http://indiatoday.intoday.in/story/delhi-changing-weather-conditions-cause-rise-in-dengue-cases/1/1075570.html?utm_source=rss\'><img src=\'http://media2.intoday.in/indiatoday/images/stories/dengue305_102617022722.jpg\' align=\"left\" hspace=\"2\" height=\"180\" width=\"305\" alt=\"\" border=\"0\"/><\/a>Usually at this time of the year, the virus becomes inactive due to \ntemperature dip. But experts are witnessing the hostile nature of ades \nmosquitoes."
  },
  {
    title  : "Waste management bye-laws pending approval of LG: Delhi High Court told",
    url    : "http://indianexpress.com/article/delhi/waste-management-bye-laws-pending-approval-of-lg-delhi-high-court-told-4906249/",
    source : "Delhi – The Indian Express",
    date   : "25.10.2017",
    desc   : "<img alt=\"\" border=\"0\" src=\"http://pixel.wp.com/b.gif?host=indianexpress.com&#038;blog=53855017&#038;post=4906249&#038;subd=indianexpressonline&#038;ref=&#038;feed=1\" width=\"1\" height=\"1\" />"
  },
  {
    title  : "Alarm bells ringing:194 dengue cases in 2 weeks in district",
    url    : "http://www.tribuneindia.com/news/ludhiana/alarm-bells-ringing-194-dengue-cases-in-2-weeks-in-district/486718.html",
    source : "The Tribune",
    date   : "25.10.2017",
    desc   : "Tribune News Service\nLudhiana, October 24\nThe number of dengue cases is rapidly increasing in the district as 194 confirmed cases have been recorded by the Health Department in the past two weeks.\nA total of 309 confirmed cases and 524 suspected cases of dengue have been reported in the district this year till Monday. According to the Health Department, cases are mostly being reported from the areas on Chandigarh Road in Ludhiana. These include 33-foot Road, GTB Nagar, Mundian Kalan, Guru Nanak Nagar, GK Estate, Jamalpur, Sectors 32 and 39. There are chances that the number of dengue cases could be higher than official reports, say residents.\nThe department had recorded 31 confirmed dengue cases till September 22 and 115 cases till October 10 in these places. Apart from these cases, as many as 10 confirmed cases of chikungunya, which is also spread by bite of infected aedes mosquitoes, have been reported here this year.\nHealth team finds mosquito larvae in 438 containers\nHealth Inspector Manpreet Singh ..."
  },
  {
    title  : "Alarm bells ringing:194 dengue cases in 2 weeks in district",
    url    : "http://www.tribuneindia.com/news/ludhiana/alarm-bells-ringing-194-dengue-cases-in-2-weeks-in-district/486718.html",
    source : "The Tribune",
    date   : "25.10.2017",
    desc   : "Tribune News Service\nLudhiana, October 24\nThe number of dengue cases is rapidly increasing in the district as 194 confirmed cases have been recorded by the Health Department in the past two weeks.\nA total of 309 confirmed cases and 524 suspected cases of dengue have been reported in the district this year till Monday. According to the Health Department, cases are mostly being reported from the areas on Chandigarh Road in Ludhiana. These include 33-foot Road, GTB Nagar, Mundian Kalan, Guru Nanak Nagar, GK Estate, Jamalpur, Sectors 32 and 39. There are chances that the number of dengue cases could be higher than official reports, say residents.\nThe department had recorded 31 confirmed dengue cases till September 22 and 115 cases till October 10 in these places. Apart from these cases, as many as 10 confirmed cases of chikungunya, which is also spread by bite of infected aedes mosquitoes, have been reported here this year.\nHealth team finds mosquito larvae in 438 containers\nHealth Inspector Manpreet Singh ..."
  },
  {
    title  : "650 new cases of dengue, 48 of chikungunya",
    url    : "http://www.thehindu.com/news/cities/Delhi/650-new-cases-of-dengue-48-of-chikungunya/article19908528.ece",
    source : "Hindu: Cities",
    date   : "24.10.2017",
    desc   : "More than 1,000 dengue cases reported so far this month"
  },
  '' // Last item -- needed because previous item ends with a comma
]`

你可以看到示例数据是无效的JSON,我尝试了下面的函数,但最终导致了键中不必要的空间,这也是一个问题。 `

//Step 1
        function extractjson(strarg){
                var found = [],          // an array to collect the strings that are found
                    rxp = /{([^}]+)}/g,

                    curMatch;
var parsed=[];
                    // step 2: regex to add quotes
                    var objKeysRegex = /({|,)(?:\s*)(?:')?([A-Za-z_$\.][A-Za-z0-9_ \-\.$]*)(?:')?(?:\s*):/g;
                    while( curMatch = rxp.exec( strarg ) ) {

                        found.push( curMatch[0].replace(objKeysRegex, "$1\"$2\":") );
                    }

                //step 3- parse the found data
                for(i=0;i<found.length;i++){
                    try {
                      json = JSON.parse(found[i]);
                    } catch (exception) {
                      json = null;
                    }
                if (json) {

                  //the json is ok
                parsed.push(JSON.parse(found[i]));

                }else{
                console.log("badjson");
      //the json is not ok

                }
            }
            console.log("input length =", found.length, "output length=", parsed.length);

            return parsed;
            }
            }

`

2 个答案:

答案 0 :(得分:1)

这是一个相当天真的解析尝试......它对数据的格式做了一些假设(例如,它在变量名上查找_nr_前缀)。我建议将字符串拆分为各种var声明,然后在使用JSON.parse进行评估之前清理它们之间的每个数据部分。

&#13;
&#13;
let parseJSON = (text) => {
  let quoteKeysAndParse = (text) => {
     //Quote keys in objects
     let quoted = text.replace(/([\{\[,]\s*)(['"])?([a-zA-Z0-9_]+)(['"])?\s*:/g, '$1"$3": ');
     //Remove the "last item" text
     quoted = quoted.replace(/,\s+'' \/\/ Last item[^\]^}]+([\]\}])/g, '$1');
     //Remove improperly escaping of apostrophes
     quoted = quoted.replace(/([^\\])\\'/g, '$1\'');
     //Parse the JSON
     return JSON.parse(quoted);
  }
  
  //Find var declarations
  let declarations = text.match(/var\s+_nr_[^\s]+\s+=\s+/ig), obj = {}, key = null, prevKey = null;
  text = ['',text];
  //For each variable...
  for(let declaration of declarations){
    key = declaration.match(/_nr_[^\s]+/)[0];
    let currentText = text[1].split(declaration);
    text = currentText;
    if(prevKey){
      //Parse the prior split section
      obj[prevKey] = quoteKeysAndParse(text[0]);
    }
    prevKey = key;
  }
  
  //Make sure we process the last section
  if(prevKey){
    obj[prevKey] = quoteKeysAndParse(text[1]);
  }
  return obj;
}

fetch('https://cors-anywhere.herokuapp.com/newsrack.in/stories/servelots/iihs_feeds/16.json')
.then(response => response.text())
.then(parseJSON)
.then(data => {
   for(let item of data._nr_stories){
      let div = document.createElement('div');
      div.innerHTML = `<h3>${item.date} - <a href="${item.url}">${item.title}</a> (${item.source})</h3><p>${item.desc}</p>`;
      document.body.append(div)
   }
});
&#13;
&#13;
&#13;

答案 1 :(得分:0)

这是一个简短的解决方案

  // ----------------------- DATA -----------------------
  let code = `
  var _nr_metadata = {
    site_base_url : "http://newsrack.in",
    issue_name    : "iihs_feeds",
    category_name : "Chikungunya",
    listing_url   : "/stories/servelots/iihs_feeds/16"
  }
  var _nr_stories = [
    {
      title  : "Alarm bells ringing:194 dengue cases in 2 weeks in district",
      url    : "http://www.tribuneindia.com/news/ludhiana/alarm-bells-ringing-194-dengue-cases-in-2-weeks-in-district/486718.html",
      source : "The Tribune",
      date   : "25.10.2017",
      desc   : "Tribune News Service\nLudhiana, October 24\nThe number of dengue cases is rapidly increasing in the district as 194 confirmed cases have been recorded by the Health Department in the past two weeks.\nA total of 309 confirmed cases and 524 suspected cases of dengue have been reported in the district this year till Monday. According to the Health Department, cases are mostly being reported from the areas on Chandigarh Road in Ludhiana. These include 33-foot Road, GTB Nagar, Mundian Kalan, Guru Nanak Nagar, GK Estate, Jamalpur, Sectors 32 and 39. There are chances that the number of dengue cases could be higher than official reports, say residents.\nThe department had recorded 31 confirmed dengue cases till September 22 and 115 cases till October 10 in these places. Apart from these cases, as many as 10 confirmed cases of chikungunya, which is also spread by bite of infected aedes mosquitoes, have been reported here this year.\nHealth team finds mosquito larvae in 438 containers\nHealth Inspector Manpreet Singh ..."
    },
    {
      title  : "650 new cases of dengue, 48 of chikungunya",
      url    : "http://www.thehindu.com/news/cities/Delhi/650-new-cases-of-dengue-48-of-chikungunya/article19908528.ece",
      source : "Hindu: Cities",
      date   : "24.10.2017",
      desc   : "More than 1,000 dengue cases reported so far this month"
    },
  ]
  `

  // --------------------- / DATA ------------------------


  // --------------------- TREATMENT ------------------------

  
  // Add '"' around the property names
  
  code = code.replace(/\n +([a-z_]+) +:/g, '"$1" :').replace(/[\n\r]/g,'');

  // To avoid unecessary ',' in "}, ]"
  
  code = code.replace(/\},[ ]*\]/g,'}]');


  // Split by var (keeping var name)
  
  code = code.split(/ var(?=[a-z_ ]+= [\[\{])/);
    
  // The result to feed
    
  let result = {} ;

  // Treat each var
  
  code.forEach( d => {

    d = d.trim();
    if (!d) { return }
    
    // Separate var name and var value
    // Faster?
    let index = d.indexOf('=');
    let var_name = d.substr(0, index).trim();
    let var_value = d.substr(index+1, d.length).trim();

    // Parse the value
    
    try 
    {
      result[var_name] = JSON.parse(var_value);
    } 
    catch(error)
    {
      console.error(error);
    }
  })
  
  console.log(result);