2012-05-13 35 views
9

Una llamada AJAX devuelve un texto de respuesta que incluye una cadena JSON. Necesito:Extraer JSON del texto

  1. extraer la cadena JSON
  2. modificarlo
  3. vuelva a introducirla para actualizar la cadena original

No estoy demasiado preocupado por los pasos 2 y 3, pero no puedo 'No entiendo cómo hacer el paso 1. Estaba pensando en usar una expresión regular, pero no sé cómo mi JSON podría tener múltiples niveles con objetos o matrices anidados.

+2

No eres nuevo aquí. ¿Qué has intentado? ¿Cómo es tu respuesta? –

+0

Además, RegEx probablemente no sea la herramienta correcta para el trabajo. –

+0

@Truth mi única solución hasta el momento es incluir marcadores en el texto de respuesta para mostrar el principio y el final de la cadena JSON. No hay nada de qué enorgullecerse o eso guiaría la respuesta. – Christophe

Respuesta

9

No puede usar una expresión regular para extraer JSON de un texto arbitrario. Como las expresiones regulares generalmente son not powerful enough to validate JSON (a menos que pueda usar PCRE), tampoco pueden coincidir; si pudieran, también podrían validar JSON.

Sin embargo, si se sabe que el elemento de nivel superior de su JSON es siempre un objeto o una matriz, se puede ir por el siguiente enfoque:

  • encontrar la primera abertura ({ o [) y el último cierre (} o ]) abrazadera en su cadena.
  • Trate de analizar ese bloque de texto (incluidos los paréntesis) usando JSON.parse(). Si tuvo éxito, finaliza y devuelve el resultado analizado.
  • Tome la llave de cierre anterior e intente analizar esa cadena. Si tiene éxito, has terminado de nuevo.
  • Repite esto hasta que no tengas ninguna llave o una que venga antes de la abrazadera de apertura actual.
  • Busque la primera abrazadera de apertura después de la del paso 1. Si no encontró ninguna, la cadena no contiene un objeto/matriz JSON y puede detenerse.
  • Ir al paso 2.

Aquí es una función que extrae un objeto JSON y devuelve el objeto y su posición. Si realmente necesita arreglos de alto nivel, también, que debe ser ampliar:

function extractJSON(str) { 
    var firstOpen, firstClose, candidate; 
    firstOpen = str.indexOf('{', firstOpen + 1); 
    do { 
     firstClose = str.lastIndexOf('}'); 
     console.log('firstOpen: ' + firstOpen, 'firstClose: ' + firstClose); 
     if(firstClose <= firstOpen) { 
      return null; 
     } 
     do { 
      candidate = str.substring(firstOpen, firstClose + 1); 
      console.log('candidate: ' + candidate); 
      try { 
       var res = JSON.parse(candidate); 
       console.log('...found'); 
       return [res, firstOpen, firstClose + 1]; 
      } 
      catch(e) { 
       console.log('...failed'); 
      } 
      firstClose = str.substr(0, firstClose).lastIndexOf('}'); 
     } while(firstClose > firstOpen); 
     firstOpen = str.indexOf('{', firstOpen + 1); 
    } while(firstOpen != -1); 
} 

var obj = {'foo': 'bar', xxx: '} me[ow]'}; 
var str = 'blah blah { not {json but here is json: ' + JSON.stringify(obj) + ' and here we have stuff that is } really } not ] json }} at all'; 
var result = extractJSON(str); 
console.log('extracted object:', result[0]); 
console.log('expected object :', obj); 
console.log('did it work  ?', JSON.stringify(result[0]) == JSON.stringify(obj) ? 'yes!' : 'no'); 
console.log('surrounding str :', str.substr(0, result[1]) + '<JSON>' + str.substr(result[2])); 

Demo (ejecutado en el entorno nodejs, pero debería funcionar en un navegador, también): https://paste.aeum.net/show/81/

+0

Interesante ... Su enlace apunta a una página que dice "Sí, es posible una validación de expresiones regulares completa". – Christophe

+0

Oh heh, no pasé de largo la respuesta aceptada, pero bueno, PCRE es bastante poderoso. No creo que esas características estén disponibles en JavaScript. – ThiefMaster

0

Si el JSON se devuelve como parte de una respuesta ajax, ¿por qué no utilizar el análisis nativo JSON de los navegadores (tenga cuidado con gotchas)? O jQuery JSON Parsing?

Si el JSON está totalmente destrozado con el texto, realmente apesta a un problema de diseño en mi humilde opinión. Si puede cambiarlo, le recomiendo hacerlo (es decir, devolver un solo objeto JSON como respuesta, con el texto como una propiedad del objeto).

Si no, usar RegEx va a ser una pesadilla absoluta. JSON es, naturalmente, muy flexible, y garantizar un análisis preciso no solo llevará mucho tiempo, sino que será un desperdicio. Probablemente pondría marcadores de contenido al principio/final y espero lo mejor. Pero vas a estar abierto a errores de validación, etc.

+0

Lamentablemente no puedo cambiarlo. Lo que obtengo en la respuesta es en realidad un guión completo que incluye parámetros en un literal JSON. – Christophe

+0

Estoy confundido, ya que en su comentario sobre la pregunta, ¿ha agregado marcadores al comienzo/final de la cadena JSON? ¿Cómo hiciste eso sin poder cambiar la respuesta? –

+0

Lo siento, lo que quiero decir es que no puedo evitar que el JSON se mezcle con "texto", siendo el texto realmente un script. – Christophe

1

Para otros que buscan (como yo) extraer cadenas de texto JSON en general (incluso si no son válidas), puedes tomar un vistazo a este plugin de Gulp https://www.npmjs.com/package/gulp-extract-json-like.Busca todas las cadenas que parecen formateadas como cadenas JSON.

Crea una carpeta e instala paquetes.

mkdir project && cd project 
npm install gulp gulp-extract-json-like 

Crear un archivo ./gulpfile.js y poner siguiente contenido en él:

var gulp = require('gulp'); 
var extractJsonLike = require('gulp-extract-json-like'); 

gulp.task('default', function() { 
    return gulp.src('file.txt') 
    .pipe(extractJsonLike()) 
    .pipe(gulp.dest('dist')); 
}); 

crear un archivo llamado ./file.txt que contiene el texto y ejecute el siguiente comando.

gulp 

Las cadenas encontradas de JSON estarán en el ./dist/file.txt.