Tengo una aplicación de nodo de la que obtengo algunos datos. He pasado por otras preguntas sobre SO ... pero no puedo resolver esto. Necesito acceder al valor de resultado . El siguiente código muestra la respuesta exacta que obtengo del servidor. Ninguno de los métodos descritos en otras respuestas como JSON.parse (), etc. parece funcionar.

    [{
      query: {
                "parameter1": "12",
                "parameter2": "13",
                "parameter3": 25
               }
      result: 6.58443
    }]

EDITAR: Como se menciona en los comentarios a continuación, desafortunadamente no puedo arreglar esto en el lado del servidor (Viene de una fuente externa). Tengo que lidiar con este JSON roto por mi parte y extraer el valor del resultado. EDIT 2: Sí, hay múltiples matrices como esta. El contenido y la parte de coma no cambian. Se enumeran uno tras otro.

0
SeaWarrior404 27 feb. 2018 a las 19:26

4 respuestas

La mejor respuesta

A pesar de que no puede recibir esos datos a través de cualquier función de biblioteca que espere JSON como jQuery $ .ajax () con la opción dataType='json' (debe usar dataType="text" en este caso para evitar que se active un error prematuro I media).

... obviamente necesita corregir la sintaxis de JSON antes de analizarla (como entendí que ya sabe).

Si es lo que está pidiendo, su mejor opción es buscar y reemplazar expresiones regulares.

Si sabe que no obtendrá cosas como '{bracket: "}"}' es bastante simple:

Ejemplo:

var wrong = `
    [{
      "query": {
                "parameter1": "12",
                "parameter2": "13",
                "parameter3": 25
               }
      "result": 6.58443
    }]
`;

var good = wrong.replace(/}(?!\s*[,}\]])/g, '},');

var json = JSON.parse(good);

console.log(json);

Este es el ejemplo más simple que corrige la entrada que proporcionó.

A pesar de que no soluciona el mismo problema después de un final de matriz (']') y, lo más importante, si se solucionó (o simplemente la cadena terminó con '}' en lugar de ']' agregaría un 'extra' , 'al final arruinando las cosas otra vez.

Un enfoque más cortés para resolver los problemas mencionados es reemplazar la fila var good = ... en el código anterior con esta:

var good = wrong.replace(/(}|])(?!\s*[,}\]])/g, '$1,')
    .replace(/,\s*$/, '')
;

Ahora, tiene un objeto json válido, por lo que acceder a cualquier propiedad es bastante obvio. Por ejemplo, json[0].result es lo que solicitó.

Por otro lado, si puede tener corchetes dentro de cadenas literales, será mucho más difícil (incluso no imposible). Pero me doy cuenta de que difícilmente sería el caso ...

2
bitifet 27 feb. 2018 a las 17:19

Lo que puede hacer es encapsular su resultado con marcas de retroceso para tener un literal de cadena (válido), luego obtener el resultado con cualquier método que desee, por ejemplo, una expresión regular coincidente:

var arr =  `[{
      "query": {
                "parameter1": "12",
                "parameter2": "13",
                "parameter3": 25
               }
      "result": 6.58443
}]`;

var match = arr.match(/("result": )(\d*.\d*)/);

console.log(match[2]);
0
scraaappy 27 feb. 2018 a las 16:56

Las sugerencias proporcionadas anteriormente ... todos apuntan a una forma hacky de resolver esto. La única forma de resolver este problema fue con la ayuda de buenas expresiones antiguas de Regex. Para mi sorpresa ... aunque hay muchas bibliotecas para manejar el análisis JSON, etc., para resolver casos extremos (común cuando se trata de clientes pequeños o fuentes de datos poco confiables), no hay una biblioteca que pueda manejar este escenario. La respuesta de @ Bitifet es lo que resuelve este problema ... con regex.

0
SeaWarrior404 28 feb. 2018 a las 05:13

Solo para fines ilustrativos, el siguiente código "reescribe" JSON que falta comas en JSON que tiene comas en los lugares apropiados. La ventaja de usar esto sobre un replace o una expresión regular es que este código garantiza que los literales de cadena se manejen correctamente:

const LEX_EXPR = (
  '('
    + '"(?:\\\\(?:["\\\\/bfnrt]|u[a-fA-F0-9]{4})|[^"])*"|'
    + '-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|'
    + '(?:true|false|null)'
  + ')|'
  + '([{\\[])|'
  + '([}\\]])|'
  + '([:,])|'
  + '(\\s+)|'
  + '(.)'
)

function lex(string) {
  let tokens = []
  let expr = new RegExp(LEX_EXPR, 'mguy')
  let match = expr.exec(string)
  while(match !== null) {
    let [
      value,
      atom,
      begin, end, sep,
      whitespace,
      junk
    ] = match
    let type
    if (atom != null) {
      type = "atom"
    } else if (begin != null) {
      type = "begin"
    } else if (end != null) {
      type = "end"
    } else if (sep != null) {
      type = "sep"
    } else if (whitespace != null) {
      type = "whitespace"
    } else {
      // junk. ignore or raise exception
      throw `Invalid character: ${junk}`
    }
    tokens.push({ type, value })
    match = expr.exec(string)
  }
  return tokens
}

function shouldInsertComma(prev, cur) {
  if (!prev || !cur) {
    return false
  }
  if (prev.type == "begin" || prev.type == "sep") {
    return false
  }
  return cur.type == "begin" || cur.type == "atom"
}

function rewrite(tokens) {
  let out = []
  let prevNonWhitespace = null
  for (let i = 0; i < tokens.length; i++) {
    let cur = tokens[i]
    if (cur.type !== "whitespace") {
      if (shouldInsertComma(prevNonWhitespace, cur)) {
        out.push({ type: "sep", value: "," })
      }
      prevNonWhitespace = cur
    }
    out.push(cur)
  }
  return out
}

function joinTokens(tokens) {
  return tokens.map(({ value }) => value).join('')
}

const invalid = `
{
  "foo": {
    "bat": "bing}"
    "boo": "bug"
  }
  "result": "yes"
}
`
const rewritten = joinTokens(rewrite(lex(invalid)))
console.log(JSON.parse(rewritten))  // { foo: { bat: 'bing}', boo: 'bug' }, result: 'yes' }
0
Joel Cornett 28 feb. 2018 a las 19:00