jq語言
編程範型 | 純函數式, 面向JSON處理, 隱式 |
---|---|
設計者 | Stephen Dolan |
面市時間 | 2012年8月21日 |
當前版本 |
|
實作語言 | jq: C gojq: Go jaq: Rust jqjq: jq |
系統平台 | 跨平台[a] |
作業系統 | 跨平台[b] |
許可證 | MIT[c] |
網站 | jqlang |
啟發語言 | |
JSON, sed, Icon |
jq是高級領域特定的詞法作用域的函數式編程語言,在其中所有JSON值都是常量。jq支持回溯和管理JSON數據的無限長字串流。它有關於Icon和Haskell程式語言。此語言支持基於名字空間的模塊系統,並對閉包有一定支持。特別是,函數和泛函表達式可以用作其他函數的參數。
歷史
[編輯]jq由Stephen Dolan創建並在2012年10月發行[4][5] 。它被設計為「針對JSON數據的sed類似者」[6]。在jq版本1.5中增加支持了正則表達式。
針對jq的叫做yq的「包裝器」[7],增加支持了YAML、XML和TOML。它首次發行於2017年[8]。
用Go實現的gojq最初發行於2019年[9],gojq顯著的擴展jq包括了支持YAML。
用Rust實現的jaq,其項目目標是更快速和更準確的jq實現,仍保持與jq在大多數情況下的兼容性。在2024年3月在其目標中排除了jq的特定高級特徵,比如模塊、SQL風格算子和給非常大JSON文檔的串流解析器[10]。
用jq實現的jqjq,最初發行於2022年。jqjq顯著的可以運行自身,擁有REPL並支持eval
。
用法
[編輯]命令行用法
[編輯]jq典型的用於命令行,並可以協作於其他命令行實用工具,比如curl。下面的例子展示如何將curl
命令的輸出通過管道接轉到jq過濾器,從而確定同這個Wikipedia頁面關聯的範疇名字:
$ URL='https://zh.wikipedia.org/w/api.php?action=parse&page=Jq%E8%AF%AD%E8%A8%80&format=json'
$ curl -s ${URL} | jq '.parse.categories[]."*"'
這個流水線產生的輸出,由JSON字符串的串流組成,它們是:
"小寫標題"
"CS1英语来源_(en)"
"动态类型编程语言"
"函数式编程语言"
"2012年建立的程式語言"
"数据查询语言"
"2012年软件"
上述curl
命令對這個頁面使用了MediaWiki API來產生JSON響應。管道|
允許curl
的輸出由jq來訪問,它是標準的Unix shell機制[11]。
展示的jq過濾器是如下jq流水線的簡寫:
.["parse"] | .["categories"] | .[] | .["*"]
這對應於curl
調用所產生的嵌套JSON結構。注意jq流水線的構造方式,同Unix風格流水線一樣,採用|
字符。
嵌入式用法
[編輯]C語言和Go實現二者都提供函數庫,使得jq函數可以嵌入到其他應用和編程環境值中。
例如,gojq已經集成於SQLite,故而jq
函數可以在其SQL語句中獲得到[12]。這些函數被標記為「確定性的」[13],故而可以被用在CREATE INDEX
命令中[14]。
運算的模態
[編輯]jq預設的充當針對JSON輸入的「串流編輯器」,非常像被當作多行文本的「串流編輯器」的sed實用工具。但是jq有一些其他運算模態:
- 它可以將來自一個或多個來源的輸入當作文本的諸行;
- 它可以將來自特定來源的輸入的串流收集到一個JSON數組之中;
- 它可以使用所謂的「串流解析器」解析其輸入,產生針對所有「葉子」路徑的
[path, value]
數組的串流。
「串流解析器」(streaming parser),在一個或多個JSON輸入太大無法載入內存之時特別有用,因為它需求的內存典型的相當小。例如,對於任意大的JSON對象的數組,峰值內存需求不比處理最大頂層對象所需要的多出很多。
這些運算模態可以在特定限制下組合起來。
語法和語義
[編輯]類型
[編輯]所有JSON值自身是jq中的值,它們從而有在下列表格中展示的類型[15]。gojq和jaq實現區分整數和非整數的數。gojq實現支持無界精度整數算術,同於jq採用Haskell的最初實現。
類型 | 例子 |
---|---|
"number" |
|
"string" |
|
"boolean" |
|
"array" |
|
"object" |
|
"null" |
|
null
是一個值[16],就像任何其他JSON純量一樣;它不是指針或空指針。nan
(對應於NaN)和infinite
(參見IEEE 754),是僅有的兩個不是JSON值的jq純量。
形式
[編輯]有用於函數創建、條件、串流歸約和模塊系統的特殊語法形式。
過濾器
[編輯]jq是面向JSON的程式語言,使用|
符號來連接過濾器形成流水線。例如:
$ jq -n '[1,2] | add'
3
這裡的JSON數組是求值為數組的一個jq過濾器。
儘管類似於Unix流水線,jq流水線允許將到來數據如同並行的發送到在|
右手端的多於一個接收者。例如,程序add/length
將計算數組中數的平均,故而:
$ jq -n '[1,2] | add/length'
1.5
$ jq -nc '[1,2] | [length, add, add/length]'
[2,3,1.5]
點號.
可以被用來在右手端定義一個附著點(attachment point),例如:
$ jq -nc '1 | [., .]'
[1,1]
$ jq -n '2 | pow(.; .)'
4
$ jq -c '. as $n | [1,0,1] | [recurse(select(.[0] < $n) | [.[0]+1, .[2], .[1]+.[2]]) | .[2]]'
1
[1]
2
[1,1]
3
[1,1,2]
6
[1,1,2,3,5,8]
下面將其定義為新的命名過濾器:
def fib: . as $n
| [1,0,1]
| [recurse(select(.[0] < $n)
| [.[0]+1, .[2], .[1]+.[2]])
| .[2]];
下面的例子展示如何定義命名的參數化的過濾器,它格式化從2到36含二者的任何基數的整數:
# Use gojq for infinite precision integer arithmetic
def tobase($b):
def digit: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"[.:.+1];
def mod: . % $b;
def div: ((. - mod) / $b);
def place_values: recurse(select(. >= $b) | div) | mod;
select(2 <= $b and $b <= 36)
| [place_values | digit] | reverse | add;
將其保存入tobase.jq
文件,接著使用這個函數:
$ jq 'include "./tobase"; tobase(16)'
17
"11"
下一個例子展示使用生成器於經典的「SEND+MORE=MONEY」覆面算遊戲:
def send_more_money:
def choose(m;n;used): ([range(m;n+1)] - used)[];
def num(a;b;c;d): 1000*a + 100*b + 10*c + d;
def num(a;b;c;d;e): 10*num(a;b;c;d) + e;
first(
1 as $m
| 0 as $o
| choose(8;9;[]) as $s
| choose(2;9;[$s]) as $e
| choose(2;9;[$s,$e]) as $n
| choose(2;9;[$s,$e,$n]) as $d
| choose(2;9;[$s,$e,$n,$d]) as $r
| choose(2;9;[$s,$e,$n,$d,$r]) as $y
| select(num($s;$e;$n;$d) + num($m;$o;$r;$e) ==
num($m;$o;$n;$e;$y))
| [$s,$e,$n,$d,$m,$o,$r,$e,$m,$o,$n,$e,$y]);
send_more_money
將其保存入send_more_money.jq
文件,接著使用這個函數:
$ jq -nc -f ./send_more_money.jq
[9,5,6,7,1,0,8,5,1,0,6,5,2]
解析表達式文法
[編輯]在jq和解析表達式文法(PEG)形式化之間有密切關聯[17]。這種關聯源於下列表格中展示的PEG七個基本運算與jq構造之間的等價性。
PEG運算名字 | PEG表示法 | jq運算或def |
---|---|---|
序列 | e1 e2
|
e1 | e2
|
有序選擇 | e1 / e2
|
e1 // e2
|
零或多個 | e*
|
def star(E): (E | star(E)) // . ;
|
一或多個 | e+
|
def plus(E): E | (plus(E) // . );
|
可選 | e?
|
def optional(E): E // .;
|
與斷言 | &e
|
def amp(E): . as $in | E | $in;
|
非斷言 | !e
|
def neg(E): select( [E] == [] );
|
移植和變體
[編輯]gojq是「純Go」實現。還有Rust實現的jq方言叫做jaq[10],它規定了指稱語義[18]。
注釋
[編輯]參考書目
[編輯]- Janssens, Jeroen. Data Science at the Command Line. O'Reilly Media. 2021. ISBN 9781492087885 (英語).
- Janssens, Jeroen. Data Science at the Command Line: Facing the Future with Time-Tested Tools. O'Reilly Media. 2014. ISBN 9781491947807 (英語).
- Marrs, Tom. JSON at Work: Practical Data Integration for the Web. O'Reilly Media. 2017. ISBN 9781491982419 (英語).
引用
[編輯]- ^ Release jq 1.7.1.
- ^ 2.0 2.1 2.2 Download jq. jq. [January 6, 2023].
- ^ Initial · jqlang/Jq@eca89ac. GitHub.
- ^ Janssens 2014.
- ^ jq. jq. [January 6, 2023].
- ^ like sed. (原始內容存檔於2013-04-14).
- ^ yq
- ^ Release v2.0.0 · kislyuk/yq. GitHub.
- ^ Release v0.0.1 · itchyny/gojq. GitHub.
- ^ 10.0 10.1 01mf02/jaq: A jq clone focussed on correctness, speed, and simplicity. GitHub. [March 6, 2024].
- ^ Tutorial. jq. [January 6, 2023].
- ^ sqlite_jq. GitHub.
- ^ "deterministic"
- ^ FAQ. GitHub.
- ^ Manual. jq. [January 6, 2023].
- ^ [https://www.json.org/json-en.html null
- ^ PEG. PEG.
- ^ Färber, Michael. Denotational Semantics and a fast interpreter for jq. 2023. arXiv:2302.10576 [cs.LO].
外部連結
[編輯]- jq homepage
- gojq - the Pure Go implementation
- jaq - the Rust implementation
- jqjq - the jq implementation
- jq FAQ
- Awesome jq - curated listing of jq-related resources
- The jq Programming Language page on the Rosetta Code comparative programming tasks project site