2016-04-02 24 views
5

Làm cách nào để phân tích cú pháp một chuỗi JSON đơn giản trong Hàng loạt?Phân tích chuỗi JSON đơn giản trong Lô

Ví dụ, nếu tôi có chuỗi sau JSON:

{ "... ":" ...", "năm": năm 2016, "thời gian": "05:01" , "...": "...", }

Chuỗi JSON này có một số phần tử và hai phần tử là "năm" và "thời gian". Từ chuỗi này, tôi muốn trích xuất các giá trị cho "năm" và "thời gian" trong hai biến mà không sử dụng bất kỳ thư viện bên ngoài nào (ví dụ, tôi không muốn cài đặt tải xuống bất kỳ utils bên ngoài nào cho điều này, Windows mới cài đặt sẽ có tất cả các công cụ cần thiết để thực hiện việc này).

+1

Vì tò mò, tại sao lại là hàng loạt? JScript hoặc PowerShell sẽ đơn giản hơn cho điều này - cả hai đều có hỗ trợ riêng cho JSON. –

+1

Ok, tính năng này sẽ trông như thế nào trong PowerShell? cho tệp JSON, trả lại giá trị cho năm và thời gian trong tập lệnh theo lô. – Andrei

+1

@MarkReed: Tôi muốn thấy giải pháp PowerShell "đơn giản hơn" (mặc dù chậm hơn nhiều) ... – Aacini

Trả lời

4

Đây là giải pháp Batch + PowerShell lai. PowerShell phản đối (deserializes) văn bản JSON và xuất nó trong định dạng khóa = giá trị được bắt và được đặt làm các biến lô theo vòng lặp lô for /f. Lưu này với một phần mở rộng .bat và cho nó một shot.

<# : 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] } 

Sau đó, nếu bạn muốn chỉ có giá trị trong năm và thời gian, chỉ cần sử dụng %JSON[year]% hoặc %JSON[time]%.

Nếu bạn đang đọc JSON của mình từ tệp .json, bạn có thể có phần PowerShell đọc tệp, thay thế ($env:JSON) bằng ((gc jsonfile.json)). Sau đó, bạn sẽ không phụ thuộc chút nào vào việc liệu JSON của bạn có đa dòng và được làm đẹp hay được rút gọn hay không. Nó sẽ được deserialized tất cả cùng một trong hai cách.


Nếu tốc độ thực thi là mối quan tâm, bạn có thể thích giải pháp lai Batch + JScript. Nó deserializes JSON vào một đối tượng giống như các giải pháp PowerShell, nhưng gọi JScript từ một bối cảnh Batch là nhanh hơn so với gọi một lệnh PowerShell hoặc kịch bản từ hàng loạt.

@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]); 

Và như là trường hợp với các giải pháp PowerShell hybrid đầu tiên, bạn có thể phân tích nhiều dòng JSON bằng cách đọc các tập tin .json từ bên trong phần JScript nếu bạn muốn (bằng cách tạo ra một đối tượng Scripting.FileSystemObject và gọi các phương thức .OpenTextFile().ReadAll()).


Đây là một giải pháp hàng loạt tinh khiết, nhưng một trong đó đặt cặp giá trị key = như một mảng kết hợp để tránh dẫm chân lên %time% như giải pháp Aacini của không.Tôi thực sự nghĩ tốt hơn là phân tích cú pháp JSON như một đối tượng trong ngôn ngữ trợ giúp chứ không phải là văn bản thuần trong lô thuần túy, nhưng tôi cũng nhận ra rằng câu trả lời hay nhất không phải lúc nào cũng phổ biến nhất.

@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

Câu trả lời rất hay! Phiên bản lô đặc biệt! –

5

Có nhiều cách khác nhau, dưới đây là một.

@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 

và đây là một giây:

@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

mã này được mã hóa cứng, ví dụ nếu tôi có các phần tử khác trong json của tôi, và tôi muốn lấy chỉ năm và thời gian, làm cách nào để biết phân của chúng – Andrei

+4

@Andrei Cách tốt nhất là đặt câu hỏi bạn muốn câu trả lời. – foxidrive

+4

Đó là một nhận xét triết học khá đấy, nhưng tôi đã cập nhật câu hỏi của mình ngay bây giờ. – 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%" 

Output:

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

Một bất tiện nhỏ của phương pháp này là "thời gian" hàng loạt biến động sẽ được thay thế bằng một JSON mới, nhưng nếu bạn sử dụng lệnh setlocal, điểm này không gây ra bất kỳ sự cố nào.

+0

Câu trả lời đơn giản! –

Các vấn đề liên quan