2012-05-13 24 views
9

Ein AJAX-Aufruf gibt einen Antworttext zurück, der eine JSON-Zeichenfolge enthält. Ich muss:JSON aus Text extrahieren

  1. extrahieren Sie die JSON-String
  2. modifizieren
  3. dann wieder einstecken die ursprüngliche Zeichenfolge

Ich bin nicht allzu besorgt über die Schritte 2 und 3 zu aktualisieren, aber ich kann Ich werde Schritt 1 nicht ausführen. Ich habe darüber nachgedacht, einen regulären Ausdruck zu verwenden, aber ich weiß nicht, wie mein JSON mehrere Ebenen mit verschachtelten Objekten oder Arrays haben könnte.

+2

Sie sind nicht neu hier. Was hast du probiert? Wie sieht deine Antwort aus? –

+0

Auch RegEx ist wahrscheinlich nicht das richtige Werkzeug für den Job. –

+0

@Truth meine einzige Problemumgehung ist bisher, Markierungen in den Antworttext einzufügen, um den Anfang und das Ende der JSON-Zeichenfolge anzuzeigen. Nichts, worauf man stolz sein könnte oder das würde die Antwort leiten. – Christophe

Antwort

9

Sie können keine Regex verwenden, um JSON aus einem beliebigen Text zu extrahieren. Da Regexes normalerweise not powerful enough to validate JSON sind (es sei denn, Sie können PCRE verwenden), können sie auch nicht übereinstimmen - wenn sie könnten, könnten sie auch JSON validieren.

Wenn Sie jedoch wissen, dass die Top-Level-Element Ihrer JSON ist immer ein Objekt oder ein Array, können Sie durch den folgenden Ansatz gehen:

  • Finden Sie die erste Öffnung ({ oder [) und letzten Schließen (} oder ]) Klammer in Ihrer Zeichenfolge.
  • Versuchen Sie, diesen Textblock (einschließlich der geschweiften Klammern) mit JSON.parse() zu analysieren. Wenn es erfolgreich war, beenden Sie das geparste Ergebnis und geben Sie es zurück.
  • Nehmen Sie die vorherige schließende Klammer und versuchen Sie, diese Zeichenfolge zu analysieren. Wenn es gelingt, sind Sie wieder fertig.
  • Wiederholen Sie dies, bis Sie keine Klammer oder eine, die vor der aktuellen öffnenden Klammer kommt.
  • Suchen Sie die erste öffnende Klammer nach der aus Schritt 1. Wenn Sie keine gefunden haben, enthielt die Zeichenfolge kein JSON-Objekt/Array und Sie können anhalten.
  • Go 2.

Hier ist eine Funktion zum Schritt, der ein Objekt JSON extrahiert und gibt das Objekt und seine Position. Wenn Sie wirklich Top-Level-Arrays benötigen auch, sollte es zu erweitern sein:

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 (in der NodeJS Umgebung ausgeführt, sollte aber in einem Browser arbeiten, auch): https://paste.aeum.net/show/81/

+0

Interessant ... Ihr Link verweist auf eine Seite mit der Aufschrift "Ja, eine vollständige Regex-Validierung ist möglich"! – Christophe

+0

Oh hey, nicht an der akzeptierten Antwort vorbeirollen - aber gut, PCRE ist ziemlich mächtig. Ich denke nicht, dass diese Funktionen in JavaScript verfügbar sind. – ThiefMaster

0

Wenn die JSON wird als Teil einer Ajax-Antwort zurückgegeben, warum nicht die native JSON-Analyse des Browsers verwenden (Vorsicht vor gotchas)? Oder jQuery JSON Parsing?

Wenn der JSON vollständig mit dem Text verunstaltet ist, riecht das wirklich nach einem Design-Problem IMHO - wenn Sie es ändern können, würde ich es dringend empfehlen (dh ein einzelnes JSON-Objekt als Antwort mit dem Text zurückgeben) als eine Eigenschaft des Objekts).

Wenn nicht, dann wird die Verwendung von RegEx ein absoluter Alptraum sein. JSON ist natürlich sehr flexibel, und das genaue Analysieren wird nicht nur zeitaufwendig, sondern auch verschwenderisch. Ich würde wahrscheinlich am Anfang/Ende Inhaltsmarker setzen und auf das Beste hoffen. Aber Sie werden für Validierungsfehler usw. offen sein.

+0

Leider kann ich es nicht ändern. Was ich in der Antwort bekomme, ist eigentlich ein ganzes Skript, das Parameter in einem JSON-Literal enthält. – Christophe

+0

Ich bin verwirrt, da Sie in Ihrem Kommentar zu der Frage Marker am Anfang/Ende der JSON-Zeichenfolge hinzugefügt haben? Wie hast du das gemacht, ohne die Antwort ändern zu können? –

+0

Entschuldigung, was ich meine ist, dass ich nicht verhindern kann, dass der JSON mit "Text" gemischt wird, wobei Text tatsächlich ein Skript ist. – Christophe

1

Für andere, die (wie ich) nach JSON-Zeichenfolgen aus Text im Allgemeinen suchen (auch wenn sie nicht gültig sind), könnten Sie nehmen ein Blick auf dieses Gulp-Plugin https://www.npmjs.com/package/gulp-extract-json-like.Es sucht nach allen Zeichenfolgen, die wie JSON-Zeichenfolgen formatiert zu sein scheinen.

Erstellen Sie einen Ordner und installieren Sie die Pakete.

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

Erstellen Sie eine Datei ./gulpfile.js und folgenden Inhalt hineingesteckt:

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

eine Datei ./file.txt, die Ihren Text enthält, und führen Sie den folgenden Befehl aufgerufen erstellen.

gulp 

gefunden JSON-Strings werden in der ./dist/file.txt sein.