2016-04-02 14 views
5

Come si analizza una semplice stringa JSON in batch?Parse semplice stringa JSON in batch

Per esempio, se ho la seguente stringa JSON:

{ "... ":" ...", "anno": 2016 "tempo": "5:01" , "...": "...", }

Questa stringa JSON ha un numero di elementi e due di essi sono "anno" e "ora". Da questa stringa, voglio estrarre i valori per "year" e "time" in due variabili senza utilizzare alcuna libreria esterna (ad esempio, non voglio installare scaricare alcun programma di utilità esterno per questo, un Windows appena installato dovrebbe avere tutti gli strumenti necessari per farlo).

+1

Per curiosità morbosa, perché lotto? JScript o PowerShell sarebbero più semplici per questo: entrambi hanno il supporto nativo per JSON. –

+1

Ok, come apparirebbe in PowerShell? dato il file JSON, restituire i valori per anno e ora in uno script batch. – Andrei

+1

@MarkReed: Mi piacerebbe vedere una soluzione PowerShell così "più semplice" (anche se molto più lenta) ... – Aacini

risposta

4

Ecco una soluzione ibrida Batch + PowerShell. PowerShell oggettifica (deserializza) il testo JSON e lo invia in formato chiave = valore per essere catturato e impostato come variabili batch dal ciclo del lotto. Salvalo con un'estensione .bat e provalo.

<# : batch portion (contained within a PowerShell multi-line comment) 
@echo off & setlocal 

set "JSON={ "year": 2016, "time": "05:01" }" 

rem # re-eval self with PowerShell and capture results 
for /f "delims=" %%I in ('powershell "iex (${%~f0} | out-string)"') do set "%%~I" 

rem # output captured results 
set JSON[ 

rem # end main runtime 
goto :EOF 

: end batch/begin PowerShell hybrid code #> 

add-type -AssemblyName System.Web.Extensions 
$JSON = new-object Web.Script.Serialization.JavaScriptSerializer 
$obj = $JSON.DeserializeObject($env:JSON) 

# output object in key=value format to be captured by Batch "for /f" loop 
foreach ($key in $obj.keys) { "JSON[{0}]={1}" -f $key, $obj[$key] } 

Poi, se si desidera che solo l'anno e ora i valori, basta usare %JSON[year]% o %JSON[time]%.

Se stai leggendo il vostro JSON da un file .json, si potrebbe avere la parte PowerShell leggere il file, sostituendo ($env:JSON) con ((gc jsonfile.json)). Quindi non sarai affatto dipendente dal fatto che il tuo JSON sia multilinea e abbellito o minorato. Comunque sarà deserializzato allo stesso modo.


Se la velocità di esecuzione è un problema, è preferibile una soluzione ibrida Batch + JScript. Deserializza il JSON in un oggetto uguale alla soluzione PowerShell, ma richiamare JScript da un contesto Batch è più veloce che richiamare un comando o uno script di PowerShell da Batch.

@if (@CodeSection == @Batch) @then 
@echo off & setlocal 

set "JSON={ "year": 2016, "time": "05:01" }" 

rem // re-eval self with JScript interpreter and capture results 
for /f "delims=" %%I in ('cscript /nologo /e:JScript "%~f0"') do set "%%~I" 

rem // output captured results 
set JSON[ 

rem // end main runtime 
goto :EOF 

@end // end Batch/begin JScript hybrid code 

var htmlfile = WSH.CreateObject('htmlfile'), 
    txt = WSH.CreateObject('Wscript.Shell').Environment('process').Item('JSON'); 

htmlfile.write('<meta http-equiv="x-ua-compatible" content="IE=9" />'); 
var obj = htmlfile.parentWindow.JSON.parse(txt); 
htmlfile.close(); 

for (var i in obj) WSH.Echo('JSON[' + i + ']=' + obj[i]); 

E, come è il caso con la prima soluzione ibrida PowerShell, è possibile analizzare più righe JSON leggendo il file .json dall'interno della porzione JScript se lo si desidera (creando un oggetto Scripting.FileSystemObject e chiamando i suoi metodi .OpenTextFile() e .ReadAll()).


Ecco un'altra soluzione lotto puro, ma che definisce coppie chiave = valore come array associativo evitare botte con %time% come soluzione Aacini fa.Penso davvero che sia meglio analizzare JSON come un oggetto in un linguaggio di supporto piuttosto che come testo piatto in puro batch, ma mi rendo anche conto che la risposta migliore non è sempre la più popolare.

@echo off 
setlocal 

set "JSON={ "other": 1234, "year": 2016, "value": "str", "time": "05:01" }" 

set "JSON=%JSON:~1,-1%" 
set "JSON=%JSON:":=",%" 

set mod=0 
for %%I in (%JSON%) do (
    set /a mod = !mod 
    setlocal enabledelayedexpansion 
    if !mod! equ 0 (
     for %%# in ("!var!") do endlocal & set "JSON[%%~#]=%%~I" 
    ) else (
     endlocal & set "var=%%~I" 
    ) 
) 

set JSON[ 
+0

Ottima risposta! Specialmente la versione batch! –

5

Ci sono diversi modi, eccone uno.

@echo off 
set string={ "year": 2016, "time": "05:01" } 
set string=%string:"=% 

for /f "tokens=3,5" %%a in ('echo %string%') do set d=%%a&set t=%%b 
echo -%d%- -%t%- 
pause & goto :EOF 

ed ecco una seconda:

@echo off 
set string={ "year": 2016, "time": "05:01" } 

for /f "tokens=3,5" %%a in ('echo %string%') do set d=%%~a&set t=%%~b 
echo -%d%- -%t%- 
pause & goto :EOF 
+0

questo è hardcoded, per esempio se ho altri elementi nel mio json, e voglio recuperare solo anno e ora, come faccio a sapere i loro indo – Andrei

+4

@Andrei Il modo migliore è quello di porre la domanda a cui si desidera la risposta. – foxidrive

+4

Questo è un bel commento filosofico, ma ho aggiornato la mia domanda ora. – Andrei

5
@echo off 
setlocal 

set string={ "other": 1234, "year": 2016, "value": "str", "time": "05:01" } 

rem Remove quotes 
set string=%string:"=% 
rem Remove braces 
set "string=%string:~2,-2%" 
rem Change colon+space by equal-sign 
set "string=%string:: ==%" 
rem Separate parts at comma into individual assignments 
set "%string:, =" & set "%" 

echo other="%other%" 
echo year="%year%" 
echo value="%value%" 
echo time="%time%" 

uscita:

other="1234" 
year="2016" 
value="str" 
time="05:01" 

Un piccolo inconveniente di questo metodo è che variabile dinamico batch "tempo" sarà sostituito dal nuovo JSON, ma se si utilizza il comando setlocal, questo punto non causa alcun problema.

+0

Buona risposta semplice! –