2012-05-13 15 views
9

Una chiamata AJAX restituisce un testo di risposta che include una stringa JSON. Ho bisogno di:Estrai JSON dal testo

  1. estrarre la stringa JSON
  2. modificarlo
  3. reinserirla per aggiornare la stringa originale

Io non sono troppo preoccupato per i punti 2 e 3, ma posso Non capisco come fare il passo 1. Stavo pensando di usare un'espressione regolare, ma non so come il mio JSON possa avere più livelli con oggetti o array annidati.

+2

Non sei nuovo qui. Che cosa hai provato? Come appare la tua risposta? –

+0

Inoltre, RegEx probabilmente non è lo strumento corretto per il lavoro. –

+0

@Truth la mia unica soluzione finora è includere gli indicatori nel testo della risposta per mostrare l'inizio e la fine della stringa JSON. Niente di cui essere orgogliosi o che avrebbe guidato la risposta. – Christophe

risposta

9

Non è possibile utilizzare un'espressione regolare per estrarre JSON da un testo arbitrario. Dal momento che le espressioni regolari sono in genere not powerful enough to validate JSON (a meno che non sia possibile utilizzare PCRE), non possono eguagliarlo: se lo fossero, potrebbero anche convalidare JSON.

Tuttavia, se si sa che l'elemento di livello superiore del vostro JSON è sempre un oggetto o un array, si può andare dalla seguente approccio:

  • Trova la prima apertura ({ o [) e l'ultimo chiusura (} o ]) parentesi graffa nella stringa.
  • Prova ad analizzare quel blocco di testo (incluse le parentesi) utilizzando JSON.parse(). Se ha avuto successo, completa e restituisce il risultato analizzato.
  • Prendere la parentesi graffa precedente e provare l'analisi di quella stringa. Se ha successo, hai finito di nuovo.
  • Ripetere fino a quando non si ottiene alcun rinforzo o uno che viene prima del rinforzo di apertura corrente.
  • Trova la prima parentesi aperta dopo quella del passaggio 1. Se non la trovi, la stringa non contiene un oggetto/array JSON e puoi fermarti.
  • Andare al punto 2.

Ecco una funzione che estrae un oggetto JSON e restituisce l'oggetto e la sua posizione. Se si ha realmente bisogno array di alto livello, anche, che dovrebbe essere di estendere:

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 (eseguito in ambiente nodejs, ma dovrebbe funzionare in un browser, anche): https://paste.aeum.net/show/81/

+0

Interessante ... Il tuo link punta a una pagina che dice "Sì, è possibile una convalida completa delle espressioni regolari"! – Christophe

+0

Oh heh, non scorrere oltre la risposta accettata, ma beh, PCRE è piuttosto potente. Non penso che quelle funzioni siano disponibili in JavaScript. – ThiefMaster

0

Se il JSON viene restituito come parte di una risposta ajax, perché non utilizzare l'analisi JSON nativa del browser (attenzione da gotchas)? O jQuery JSON Parsing?

Se il JSON è completamente distrutto dal testo, che puzza davvero di un problema di progettazione IMHO - se puoi cambiarlo, ti consiglio vivamente di farlo (cioè restituire un singolo oggetto JSON come risposta, con il testo come una proprietà dell'oggetto).

In caso contrario, utilizzare RegEx sarà un vero incubo. JSON è naturalmente molto flessibile e garantire un parsing accurato sarà non solo dispendioso in termini di tempo, ma solo dispendioso. Probabilmente inserirò indicatori di contenuto all'inizio/fine e spero per il meglio. Ma sarai molto aperto agli errori di convalida ecc.

+0

Purtroppo non posso cambiarlo. Quello che sto ottenendo nella risposta è in realtà un intero script che include parametri in un letterale JSON. – Christophe

+0

Sono confuso, dal momento che nel tuo commento alla domanda hai aggiunto marcatori all'inizio/alla fine della stringa JSON? Come lo hai fatto senza essere in grado di cambiare la risposta? –

+0

Mi spiace, quello che voglio dire è che non posso impedire che il JSON venga mixato con "testo", il testo in realtà è uno script. – Christophe

1

Per gli altri che stanno cercando (come lo ero io) di estrarre stringhe JSON dal testo in generale (anche se non sono validi), potresti prendere un'occhiata a questo plugin Gulp https://www.npmjs.com/package/gulp-extract-json-like.Cerca tutte le stringhe che sembrano formattate come le stringhe JSON.

Creare una cartella e installare i pacchetti.

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

Creare un file ./gulpfile.js e mettere seguente contenuto in esso:

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')); 
}); 

creare un file chiamato ./file.txt che contiene il testo ed eseguire il seguente comando.

gulp 

Le stringhe JSON trovate saranno nello ./dist/file.txt.