.TH "JAQ" "1" "" "" .SH "نام (NAME)" .PP \f[CB]jaq\f[R] \- پردازشگر خط فرمان JSON .SH "خلاصه دستور (SYNOPSIS)" .PP \f[CB]jaq\f[R] [\f[I]OPTION\f[R]]…\ [\f[I]FILTER\f[R]]\ [\f[I]FILE\f[R]]… .SH "توضیحات (DESCRIPTION)" .PP دستور jaq مفسری برای زبان برنامه‌نویسی jq است\&. این ابزار به گونه‌ای طراحی شده است که بتواند به عنوان جایگزین مستقیم برای برنامه \f[CB]jq\f[R] (که مفسر مرجع زبان jq نوشته‌شده به زبان C است) استفاده شود\&. .PP ابزار jaq که به زبان Rust نوشته شده است، بر درستی، کارایی بالا و سادگی تمرکز دارد\&. علاوه بر این، jaq قابلیت‌هایی را اضافه می‌کند که در \f[CB]jq\f[R] وجود ندارند: .RS 2 .IP \[bu] 2 پشتیبانی از چندین قالب فایلی، از جمله JSON، YAML، CBOR، TOML، XML .IP \[bu] 2 پشتیبانی از واحدهای کُد نامعتبر UTF\-8 در رشته‌های متنی .IP \[bu] 2 رشته‌های بایتی (Byte strings) .IP \[bu] 2 اشیاء با کلیدهای غیررشته‌ای، مانند \f[CB]{0: 1, [2]: 3}\f[R] .IP \[bu] 2 جایگزینی درجا (In-place) در فایل‌های ورودی .RE .PP این راهنما تلاش دارد: .RS 2 .IP \[bu] 2 قابل‌فهم، موجز و کامل باشد\&. .IP \[bu] 2 تمام عملکردهای jaq، به ویژه رابط خط فرمان jaq، زبان هسته jq و کتابخانه استاندارد jq را مستند کند\&. این راهنما مفاهیمی مشابه \c .UR https://jqlang.org/manual راهنمای jq .UE \c را پوشش می‌دهد\&. .IP \[bu] 2 تمام تفاوت‌ها و انحراف‌ها میان \f[CB]jq\f[R] و jaq را ثبت کند\&. .RE .PP در صورتی که این راهنما نقصی در دستیابی به این اهداف دارد، لطفاً یک \c .UR https://github.com/01mf02/jaq/issues گزارش اشکال (issue) .UE \c باز کنید یا یک پول‌ریکوئست (درخواست ادغام) ارسال نمایید\&. همچنین اگر مایل به پیشنهاد قابلیت‌های جدید برای jaq هستید، همین کار را انجام دهید\&. این پروژه با مشارکت‌های شما زنده است! .PP ایجاد این صفحه راهنما از طریق \c .UR https://nlnet.nl/commonsfund NGI0 Commons Fund .UE \c تامین مالی شده است؛ صندوقی که توسط \c .UR https://nlnet.nl NLnet .UE \c با حمایت مالی برنامه \c .UR https://ngi.eu Next Generation Internet .UE \c کمیسیون اروپا، تحت نظارت \c .UR https://commission.europa.eu/about-european-commission/departments-and-executive-agencies/communications-networks-content-and-technology_en DG Communications Networks, Content and Technology .UE \c تحت قرارداد کمک مالی شماره \c .UR https://cordis.europa.eu/project/id/101135429 101135429 .UE \c تاسیس شده است\&. تامین مالی تکمیلی توسط \c .UR https://www.sbfi.admin.ch/sbfi/en/home.html کتابت دولتی سوئیس برای آموزش، پژوهش و نوآوری .UE \c (SERI) فراهم شده است\&. .PP \f[I]سازگاری\f[R] .RS این راهنما از بلوک‌های «سازگاری» برای نشان دادن مواردی که jaq از \f[CB]jq\f[R] فاصله می‌گیرد استفاده می‌کند\&. در این راهنما، «\f[CB]jq\f[R]» به پیاده‌سازی C اشاره دارد، در حالی که «jq» به خود زبان jq اشاره می‌کند\&. .RE .SH "رابط خط فرمان (COMMAND\-LINE INTERFACE)" .PP اجرای \f[CB]jaq\f[R] [\f[I]OPTION\f[R]]… [\f[I]FILTER\f[R]] [\f[I]FILE\f[R]]… مراحل زیر را انجام می‌دهد: .RS 2 .IP \[bu] 2 تجزیه (parse) کردن \f[I]FILTER\f[R] به عنوان برنامه jq؛ بخش زبان jq را ببینید .IP \[bu] 2 به ازای هر \f[I]FILE\f[R]: .RS 2 .IP \[bu] 2 تجزیه کردن \f[I]FILE\f[R] به جریانی از مقادیر .IP \[bu] 2 به ازای هر مقدار ورودی در فایل: .RS 2 .IP \[bu] 2 اجرای \f[I]FILTER\f[R] روی مقدار ورودی و چاپ مقادیر خروجی آن .RE .RE .IP \[bu] 2 اگر در هر نقطه‌ای خطای مهارنشده‌ای رخ دهد، jaq متوقف می‌شود\&. .RE .PP برای نمونه، دستور \f[CB]jaq \[aq]\&.name?\[aq] persons\&.json\f[R] ابتدا فیلتر \f[CB]\&.name?\f[R] را تجزیه می‌کند، سپس تمام مقادیر موجود در \f[CB]persons\&.json\f[R] را یکی‌یکی می‌خواند\&. سپس فیلتر \f[CB]\&.name?\f[R] را روی هر یک از مقادیر اجرا کرده و خروجی‌های فیلتر را به صورت JSON چاپ می‌کند\&. .SS "ورودی (INPUT)" .PP اگر هیچ \f[I]FILE\f[R] مشخص نشود، jaq از ورودی استاندارد می‌خواند\&. دستور jaq قالب تجزیه \f[I]FILE\f[R] را به شرح زیر تعیین می‌کند: .RS 2 .IP \[bu] 2 اگر گزینه \f[CB]\-\-from\f[R] \f[I]FORMAT\f[R] استفاده شود، jaq از همان قالب استفاده می‌کند\&. .IP \[bu] 2 در غیر این صورت، اگر \f[I]FILE\f[R] پسوند فایلی شناخته‌شده توسط jaq داشته باشد، مانند \f[CB]\&.json\f[R]، \f[CB]\&.yaml\f[R]، \f[CB]\&.cbor\f[R]، \f[CB]\&.toml\f[R]، \f[CB]\&.xml\f[R]، \f[CB]\&.csv\f[R]، \f[CB]\&.tsv\f[R]، دستور jaq از قالب متناظر آن استفاده می‌کند\&. .IP \[bu] 2 در غیر این صورت، jaq فرض می‌کند قالب ورودی JSON است\&. .RE .SS \f[CB]\-\-from\f[R] \f[I]FORMAT\f[R] .PP تفسیر تمام فایل‌های ورودی در قالب \f[I]FORMAT\f[R]\&. برای نمونه: \f[CB]jaq \-\-from yaml \&. myfile\&.yml\f[R] فایل \f[CB]myfile\&.yml\f[R] را به عنوان YAML تجزیه می‌کند\&. مقادیر ممکن برای \f[I]FORMAT\f[R] عبارتند از: \f[CB]raw\f[R]، \f[CB]raw0\f[R]، \f[CB]json\f[R]، \f[CB]yaml\f[R]، \f[CB]cbor\f[R]، \f[CB]toml\f[R]، \f[CB]xml\f[R]، \f[CB]csv\f[R]، \f[CB]tsv\f[R]\&. .PP دستور jaq به صورت خودکار قالب ورودی متناظر را برای فایل‌های با پسوندهای زیر انتخاب می‌کند: \f[CB]\&.json\f[R]، \f[CB]\&.yaml\f[R]، \f[CB]\&.yml\f[R]، \f[CB]\&.cbor\f[R]، \f[CB]\&.toml\f[R]، \f[CB]\&.xml\f[R]، \f[CB]\&.xhtml\f[R]، \f[CB]\&.csv\f[R]، \f[CB]\&.tsv\f[R]\&. این بدان معناست که دستور \f[CB]jaq \-\-from cbor \&. myfile\&.cbor\f[R] معادل است با \f[CB]jaq \&. myfile\&.cbor\f[R]\&. .PP \f[I]سازگاری\f[R] .RS برنامه \f[CB]jq\f[R] این گزینه را ندارد\&. .RE .SS \f[CB]\-n\f[R], \f[CB]\-\-null\-input\f[R] .PP ارسال مقدار \f[CB]null\f[R] به عنوان ورودی به برنامه اصلی، بدون توجه به فایل‌های ورودی\&. برای نمونه: .IP .EX $ yes | jaq \-n null .EE .PP این نشان می‌دهد که این گزینه در واقع هیچ ورودی‌ای نمی‌خواند\&. .PP ورودی‌ها همچنان از طریق فیلتر \f[CB]inputs\f[R] قابل دستیابی هستند\&. برای نمونه: .IP .EX $ yes true | jaq \-n \[aq]first(inputs)\[aq] true .EE .PP این می‌تواند برای پیمایش و تجمیع روی تمام ورودی‌ها با \f[CB]reduce\f[R] / \f[CB]foreach\f[R] مفید باشد\&. .SS \f[CB]\-R\f[R], \f[CB]\-\-raw\-input\f[R] .PP خواندن خطوط ورودی به عنوان توالی‌ای از رشته‌ها\&. برای نمونه: .IP .EX $ printf \[dq]Hello\[rs]nWorld\[dq] | jaq \-R \[dq]Hello\[dq] \[dq]World\[dq] .EE .PP هنگامی که با گزینه \f[CB]\-\-slurp\f[R] ترکیب شود، کل ورودی را به عنوان یک رشته منفرد تولید می‌کند\&. برای نمونه: .IP .EX $ printf \[dq]Hello\[rs]nWorld\[dq] | jaq \-Rs \[dq]Hello\[rs]nWorld\[dq] .EE .PP گزینه \f[CB]\-\-rawfile\f[R] را ببینید\&. .PP این گزینه معادل \f[CB]\-\-from raw\f[R] است\&. .SS \f[CB]\-\-raw\-input0\f[R] .PP خواندن مقادیر مشابه \f[CB]\-\-raw\-input\f[R]، با جداسازی توسط NUL (\f[CB]\[rs]0\f[R]) به جای خطوط جدید\&. برای نمونه: .IP .EX $ printf \[dq]Hello\[rs]nWorld\[rs]0foo\[dq] | jaq \-\-raw\-input0 \[dq]Hello\[rs]nWorld\[dq] \[dq]foo\[dq] .EE .PP هنگامی که با گزینه \f[CB]\-\-slurp\f[R] ترکیب شود، تمام ورودی‌ها را در قالب یک آرایه جمع‌آوری می‌کند\&. برای نمونه: .IP .EX $ printf \[dq]Hello\[rs]nWorld\[rs]0foo\[dq] | jaq \-sc \-\-raw\-input0 [\[dq]Hello\[rs]nWorld\[dq],\[dq]foo\[dq]] .EE .PP این گزینه می‌تواند برای بازگرداندن خروجی حاصل از \f[CB]\-\-raw\-output0\f[R] استفاده شود: .IP .EX $ printf \[aq]\[dq]some string\[rs]\[rs]nwith a newline\[dq] \[dq]another string\[dq]\[aq] | jaq \-\-raw\-output0 | jaq \-\-raw\-input0 \[dq]some string\[rs]nwith a newline\[dq] \[dq]another string\[dq] .EE .PP این گزینه معادل \f[CB]\-\-from raw0\f[R] است\&. .PP \f[I]سازگاری\f[R] .RS برنامه \f[CB]jq\f[R] این گزینه را ندارد\&. .RE .SS \f[CB]\-s\f[R], \f[CB]\-\-slurp\f[R] .PP خواندن تمام مقادیر ورودی درون یک آرایه (به ازای هر فایل)\&. برای نمونه: .IP .EX $ echo 1 2 3 | jaq 1 2 3 $ echo 1 2 3 | jaq \-cs [1,2,3] .EE .PP هنگامی که با گزینه \f[CB]\-\-raw\-input\f[R] ترکیب شود، دستور jaq کل ورودی را به عنوان یک رشته واحد می‌خواند\&. برای نمونه: .IP .EX $ echo 1 2 3 | jaq \-Rs \[dq]1 2 3\[rs]n\[dq] .EE .PP گزینه \f[CB]\-\-rawfile\f[R] را ببینید\&. .PP \f[I]سازگاری\f[R] .RS هنگامی که چندین فایل با slurp خوانده می‌شوند، برنامه \f[CB]jq\f[R] ورودی‌های تمام فایل‌ها را در یک آرایه واحد ترکیب می‌کند، در حالی که دستور jaq برای هر فایل یک آرایه تولید می‌نماید\&. دلیل این تفاوت، گزینه \f[CB]\-\-in\-place\f[R] در jaq است که نمی‌توانست با رفتار پیاده‌سازی‌شده در \f[CB]jq\f[R] کار کند\&. رفتار \f[CB]jq\f[R] در jaq قابل شبیه‌سازی است؛ برای نمونه، جهت دستیابی به خروجی دستور \f[CB]jq \-s \&. a b\f[R]، می‌توانید از \f[CB]jaq \-s \&. <(cat a b)\f[R] استفاده کنید\&. .RE .SS "خروجی (OUTPUT)" .SS \f[CB]\-\-to\f[R] \f[I]FORMAT\f[R] .PP چاپ تمام مقادیر خروجی در قالب \f[I]FORMAT\f[R] داده‌شده\&. هر قالبی که توسط \f[CB]\-\-from\f[R] پذیرفته می‌شود می‌تواند در اینجا نیز به کار رود\&. .PP توجه داشته باشید که هر مقداری را نمی‌توان در هر قالبی چاپ کرد\&. برای نمونه، در TOML الزامی است که مقدار ریشه یک شیء (object) باشد، بنابراین تلاش برای چاپ یک مقدار ریشه غیرشیئی به عنوان TOML خطایی ایجاد می‌کند: .IP .EX $ echo [] | jaq \-\-to toml 2>/dev/null; echo $? 2 .EE .PP \f[I]سازگاری\f[R] .RS برنامه \f[CB]jq\f[R] این گزینه را ندارد\&. .RE .SS \f[CB]\-c\f[R], \f[CB]\-\-compact\-output\f[R] .PP چاپ خروجی JSON به صورت فشرده، با حذف فاصله‌های خالی اضافه\&. برای نمونه: .IP .EX $ echo [1, 2, 3] | jaq \-c [1,2,3] .EE .SS \f[CB]\-r\f[R], \f[CB]\-\-raw\-output\f[R] .PP نوشتن رشته‌ها (متنی و بایتی) بدون اسکیپ کردن آن‌ها و بدون قرار دادن درون گیومه (کوتیشن)\&. برای نمونه: .IP .EX $ printf \[aq]\[dq]Hello\[rs]\[rs]nWorld\[dq]\[aq] | jaq \-r Hello World $ printf \[aq]\[dq]Hello\[rs]\[rs]nWorld\[dq]\[aq] | jaq \[dq]Hello\[rs]nWorld\[dq] .EE .PP این گزینه روی رشته‌های موجود درون مقادیر دیگر، یعنی درون آرایه‌ها و اشیاء تأثیری ندارد\&. برای نمونه: .IP .EX $ printf \[aq][\[dq]Hello\[rs]\[rs]nWorld\[dq]]\[aq] | jaq \-rc [\[dq]Hello\[rs]nWorld\[dq]] .EE .PP این گزینه معادل \f[CB]\-\-to raw\f[R] است\&. .SS \f[CB]\-\-raw\-output0\f[R] .PP خروجی دادن مقادیر مانند \f[CB]\-\-raw\-output\f[R]، با خاتمه دادن به آن‌ها با کاراکتر NUL (\f[CB]\[rs]0\f[R]) به جای LF (\f[CB]\[rs]n\f[R])\&. .IP .EX $ printf \[aq]\[dq]some string\[rs]\[rs]nwith a newline\[dq] true\[aq] | jaq \-\-raw\-output0 | jaq \-s \-\-raw\-input tobytes b\[dq]some string\[rs]nwith a newline\[rs]x00true\[rs]x00\[dq] .EE .PP هر مقدار خروجی که یک رشته حاوی NUL باشد، خطایی تولید می‌کند\&. توجه داشته باشید که این موضوع در مورد رشته‌های موجود در یک آرایه یا شیء صدق نمی‌کند\&. .IP .EX $ printf \[aq]\[dq]string with NUL \[rs]\[rs]u0000\[dq]\[aq] | jaq \-\-raw\-output0 2>/dev/null; echo $? 2 .EE .PP این گزینه معادل \f[CB]\-\-to raw0\f[R] است\&. .SS \f[CB]\-j\f[R], \f[CB]\-\-join\-output\f[R] .PP عدم چاپ نویسه خط جدید پس از هر مقدار\&. برای نمونه: .IP .EX $ echo true false | jaq \-j && echo \[dq] (no new line at end)\[dq] truefalse (no new line at end) .EE .PP این گزینه به ویژه در ترکیب با \f[CB]\-\-raw\-output\f[R] (\f[CB]\-r\f[R]) مفید است؛ برای نمونه: .IP .EX $ printf \[aq]\[dq]Hello\[dq] \[dq] \[dq] \[dq]World\[dq] \[dq]\[rs]\[rs]n\[dq]\[aq] | jaq \-jr Hello World .EE .SS \f[CB]\-i\f[R], \f[CB]\-\-in\-place\f[R] .PP بازنویسی فایل ورودی با خروجی آن به صورت درجا (in-place)\&. برای نمونه: .IP .EX $ echo 1 > tmp\&.json && jaq \-i \[aq]\&.+1\[aq] tmp\&.json && cat tmp\&.json && rm tmp\&.json 2 .EE .PP این دستور فایل \f[CB]tmp\&.json\f[R] را خوانده و آن را با خروجی فیلتر \f[CB]\&.+1\f[R] بازنویسی می‌کند\&. توجه داشته باشید که فایل ورودی تنها زمانی بازنویسی می‌شود که هیچ خروجی دیگری باقی نمانده باشد و هیچ خطایی نیز رخ نداده باشد\&. .PP \f[I]سازگاری\f[R] .RS برنامه \f[CB]jq\f[R] این گزینه را ندارد\&. .RE .SS \f[CB]\-S\f[R], \f[CB]\-\-sort\-keys\f[R] .PP چاپ اشیاء به صورت مرتب‌شده بر اساس کلیدهایشان\&. برای نمونه: .IP .EX $ echo \[aq]{\[dq]b\[dq]: {\[dq]d\[dq]: 3, \[dq]c\[dq]: 2}, \[dq]a\[dq]: 1}\[aq] | jaq \-cS {\[dq]a\[dq]:1,\[dq]b\[dq]:{\[dq]c\[dq]:2,\[dq]d\[dq]:3}} $ echo \[aq]{\[dq]b\[dq]: {\[dq]d\[dq]: 3, \[dq]c\[dq]: 2}, \[dq]a\[dq]: 1}\[aq] | jaq \-c {\[dq]b\[dq]:{\[dq]d\[dq]:3,\[dq]c\[dq]:2},\[dq]a\[dq]:1} .EE .SS \f[CB]\-C\f[R], \f[CB]\-\-color\-output\f[R] .PP رنگی کردن همیشگی خروجی، حتی اگر jaq در یک ترمینال چاپ نشود\&. برای نمونه: .IP .EX $ echo {} | jaq \-C | jaq \-\-from raw tobytes b\[dq]\[rs]x1b[1;39m{\[rs]x1b[0m\[rs]x1b[1;39m}\[rs]x1b[0m\[dq] $ echo {} | jaq | jaq \-\-from raw tobytes b\[dq]{}\[dq] .EE .PP (در اینجا، \f[CB]jaq \-\-from raw tobytes\f[R] یک نمایش بایتی از ورودی خود را چاپ می‌کند که در حالت \f[CB]\-C\f[R] شامل توالی‌های رنگی ANSI است\&.) .SS \f[CB]\-M\f[R], \f[CB]\-\-monochrome\-output\f[R] .PP عدم استفاده از رنگ در خروجی (خروجی تک‌رنگ)\&. .SS \f[CB]\-\-tab\f[R] .PP استفاده از تب (tab) برای تورفتگی به جای فاصله‌ها (spaces)\&. .PP برای نمونه: .IP .EX $ echo [1, [2]] | jaq \-\-tab | jaq \-Rs \[dq][\[rs]n\[rs]t1,\[rs]n\[rs]t[\[rs]n\[rs]t\[rs]t2\[rs]n\[rs]t]\[rs]n]\[rs]n\[dq] $ echo [1, [2]] | jaq | jaq \-Rs \[dq][\[rs]n 1,\[rs]n [\[rs]n 2\[rs]n ]\[rs]n]\[rs]n\[dq] .EE .SS \f[CB]\-\-indent\f[R] \f[I]N\f[R] .PP استفاده از \f[I]N\f[R] فاصله برای تورفتگی (پیش‌فرض: 2)\&. .SS \f[CB]NO_COLOR\f[R] .PP اگر متغیر محیطی \f[CB]NO_COLOR\f[R] روی یک مقدار غیرخالی تنظیم شده باشد، دستور jaq هیچ رنگی چاپ نمی‌کند، مگر اینکه فلگ \f[CB]\-C\f[R] استفاده شده باشد\&. .SS \f[CB]JQ_COLORS\f[R] .PP متغیر محیطی \f[CB]JQ_COLORS\f[R] فهرستی جداشده با دونقطه (colon) است که در آن هر مدخل سبکی را برای چاپ نوع خاصی از مقادیر مشخص می‌کند\&. مدخل‌های \f[CB]JQ_COLORS\f[R] به ترتیب زیر به انواع مقادیر متناظر می‌شوند: .RS 2 .IP \[bu] 2 \f[CB]null\f[R] .IP \[bu] 2 \f[CB]false\f[R] .IP \[bu] 2 \f[CB]true\f[R] .IP \[bu] 2 اعداد (numbers) .IP \[bu] 2 رشته‌ها (strings) .IP \[bu] 2 آرایه‌ها (arrays) .IP \[bu] 2 اشیاء (objects) .IP \[bu] 2 کلیدهای اشیاء (object keys) .RE .PP اگر \f[CB]JQ_COLORS\f[R] تنظیم نشده باشد، مقدار پیش‌فرض آن \f[CB]90:39:39:39:32:1;39:1;39:1;34\f[R] در نظر گرفته می‌شود\&. این بدان معناست که به طور پیش‌فرض: .RS 2 .IP \[bu] 2 مقدار \f[CB]null\f[R] دارای سبک \f[CB]90\f[R] است (رنگ پیش‌زمینه خاکستری)\&. .IP \[bu] 2 مقادیر \f[CB]false\f[R]/\f[CB]true\f[R]/اعداد دارای سبک \f[CB]39\f[R] هستند (رنگ پیش‌زمینه پیش‌فرض)\&. .IP \[bu] 2 رشته‌ها دارای سبک \f[CB]32\f[R] هستند (رنگ پیش‌زمینه سبز)\&. .IP \[bu] 2 آرایه‌ها/اشیاء دارای سبک \f[CB]1;39\f[R] هستند (پررنگ و رنگ پیش‌زمینه پیش‌فرض)\&. .IP \[bu] 2 کلیدهای اشیاء دارای سبک \f[CB]1;34\f[R] هستند (پررنگ و رنگ پیش‌زمینه آبی)\&. .RE .PP هر مدخل غیرخالی در \f[CB]JQ_COLORS\f[R]، مانند \f[CB]90\f[R] یا \f[CB]1;39\f[R]، به یک توالی کنترلی \c .UR https://en.wikipedia.org/wiki/ANSI_escape_code#Select_Graphic_Rendition_parameters «Select Graphic Rendition» .UE \c (SGR) تبدیل می‌شود\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB]32\f[R] به \f[CB]\[rs]x1b[32m\f[R] تبدیل می‌شود\&. .IP \[bu] 2 \f[CB]1;39\f[R] به \f[CB]\[rs]x1b[1;39m\f[R] تبدیل می‌شود\&. .RE .PP دستور jaq اجازه تغییر رنگ رشته‌های بایتی را نمی‌دهد، زیرا jq هیچ امکانی برای این کار فراهم نکرده است\&. .SS "کامپایل (COMPILATION)" .PP اگر هیچ \f[I]FILTER\f[R] ارائه نشود، jaq از \f[CB]\&.\f[R] (فیلتر همانی) به عنوان فیلتر استفاده می‌کند\&. .PP هنگام ارسال مستقیم فیلترها به عنوان آرگومان \f[I]FILTER\f[R] در خط فرمان، باید مراقب بود که فیلتر به درستی اسکیپ (escape) شود\&. نحوه انجام این کار به پلتفرم بستگی دارد، اما در سیستم‌های شبه‌یونیکس، قرار دادن فیلتر درون کوتیشن‌های تکی (\f[CB]\[aq]\f[R]) و جایگزینی رخدادهای \f[CB]\[aq]\f[R] در فیلترها با \f[CB]\[aq]\[rs]\[aq]\[aq]\f[R] کفایت می‌کند\&. برای نمونه، جهت اجرای فیلتر \f[CB]\[dq]\[aq]\[dq]\f[R] که رشته‌ای شامل یک کوتیشن تکی تولید می‌کند، می‌توانید بنویسید: .IP .EX $ jaq \-n \[aq]\[dq]\[aq]\[rs]\[aq]\[aq]\[dq]\[aq] \[dq]\[aq]\[dq] .EE .PP اجرای فیلترهایی که با عملگر نفی آغاز می‌شوند، مانند \f[CB]jaq \[aq]\-1\[aq]\f[R]، با شکست مواجه می‌شود زیرا \f[CB]\-\f[R] به عنوان شروع یک سوییچ خط فرمان تفسیر می‌شود نه نفی\&. می‌توانید با استفاده از \f[CB]\-\-\f[R] یا قرار دادن فیلتر در پرانتز این مشکل را برطرف کنید: .IP .EX $ jaq \-n \-\- \[aq]\-1\[aq] \-1 $ jaq \-n \[aq](\-1)\[aq] \-1 .EE .SS \f[CB]\-f\f[R], \f[CB]\-\-from\-file\f[R] .PP خواندن فیلتر از فایلی که نام آن در آرگومان فیلتر مشخص شده است\&. .PP با این گزینه، jaq آرگومان \f[I]FILTER\f[R] را به عنوان نام فایلی تفسیر می‌کند که حاوی فیلتر است\&. توجه داشته باشید که نام فایل ممکن است مستقیماً پس از این گزینه نیاید\&. برای نمونه: .IP .EX $ echo \[aq]2 * 21\[aq] > tmp\&.jq && jaq \-\-from\-file \-n tmp\&.jq && rm tmp\&.jq 42 .EE .SS \f[CB]\-L\f[R], \f[CB]\-\-library\-path\f[R] \f[I]DIR\f[R] .PP جستجو برای ماژول‌ها و داده‌ها در دایرکتوری مشخص‌شده\&. .PP دستور jaq ماژول‌ها و داده‌ها را در مجموعه‌ای از پوشه‌ها به نام «مسیرهای جستجو» جستجو می‌کند\&. استفاده از \f[CB]\-\-library\-path\f[R] دایرکتوری جدیدی را به مسیرهای جستجوی سراسری اضافه می‌کند\&. .PP برای نمونه: \f[CB]jaq \-L \&. \-L \&.\&. \[aq]include \[dq]script\[dq]; foo\[aq]\f[R] فایل \f[CB]script\&.jq\f[R] را ابتدا در پوشه جاری و سپس در پوشه والد جستجو می‌کند\&. .PP اگر گزینه \f[CB]\-\-library\-path\f[R] داده نشود، مسیرهای جستجوی سراسری زیر استفاده می‌شوند: .RS 2 .IP \[bu] 2 \f[CB]~/\&.jq\f[R] .IP \[bu] 2 \f[CB]$ORIGIN/\&.\&./lib/jq\f[R] .IP \[bu] 2 \f[CB]$ORIGIN/\&.\&./lib\f[R] .RE .PP برای جزئیات بیشتر بخش ماژول‌ها را ببینید\&. .SS "متغیرها (VARIABLES)" .SS \f[CB]\-\-arg\f[R] \f[I]A\f[R] \f[I]V\f[R] .PP تنظیم متغیر \f[CB]$A\f[R] با مقدار رشته‌ای \f[I]V\f[R]\&. .PP برای نمونه: .IP .EX $ jaq \-\-arg name \[dq]John Doe\[dq] \-n \[aq]\[dq]Welcome, \[dq] + $name\[aq] \[dq]Welcome, John Doe\[dq] .EE .SS \f[CB]\-\-argjson\f[R] \f[I]A\f[R] \f[I]V\f[R] .PP تنظیم متغیر \f[CB]$A\f[R] با مقدار JSON با نام \f[I]V\f[R]\&. .PP برای نمونه: .IP .EX $ jaq \-\-argjson song \[aq]{\[dq]name\[dq]: \[dq]One of Us\[dq], \[dq]artist\[dq]: \[dq]ABBA\[dq], \[dq]year\[dq]: 1981}\[aq] \-n \[rs] \[aq]\[dq]Currently playing: \[rs]($song\&.name) (\[rs]($song\&.year))\[dq]\[aq] \[dq]Currently playing: One of Us (1981)\[dq] .EE .PP اگر \f[I]V\f[R] بیش از یک مقدار منفرد داشته باشد، مثلاً \f[CB]1 2\f[R]، دستور jaq خطایی صادر می‌کند\&. .SS \f[CB]\-\-slurpfile\f[R] \f[I]A\f[R] \f[I]F\f[R] .PP تنظیم متغیر \f[CB]$A\f[R] با یک آرایه حاوی مقادیر JSON در فایل \f[I]F\f[R]\&. .PP برای نمونه: .IP .EX $ echo 1 2 3 > tmp\&.json && jaq \-\-slurpfile xs tmp\&.json \-cn \[aq]$xs\[aq] && rm tmp\&.json [1,2,3] .EE .SS \f[CB]\-\-rawfile\f[R] \f[I]A\f[R] \f[I]F\f[R] .PP تنظیم متغیر \f[CB]$A\f[R] با رشته‌ای حاوی محتویات فایل \f[I]F\f[R]\&. .PP دستور jaq تلاش می‌کند فایل را از طریق نگاشت حافظه (memory mapping) بارگذاری کند، که زمان ثابت مصرف می‌کند و امکان بارگذاری فایل‌هایی را می‌دهد که در حافظه جا نمی‌شوند\&. در صورت عدم موفقیت، jaq فایل را به صورت عادی و با زمان خطی بارگذاری می‌کند\&. این دقیقاً همان چیزی است که هنگام استفاده از \f[CB]\-Rs\f[R] (\f[CB]\-\-raw\-input\f[R] و \f[CB]\-\-slurp\f[R]) جهت بارگذاری یک فایل (برخلاف ورودی استاندارد) رخ می‌دهد\&. .PP \f[I]سازگاری\f[R] .RS برخلاف \f[CB]jq\f[R]، دستور jaq بررسی نمی‌کند که آیا فایل UTF\-8 معتبر است یا خیر\&. این موضوع امکان بارگذاری فایل‌های باینری دلخواه را می‌دهد؛ این فایل‌ها می‌توانند از طریق \f[CB]tobytes\f[R] به عنوان رشته‌های بایتی پردازش شوند\&. .RE .SS \f[CB]\-\-args\f[R] .PP جمع‌آوری آرگومان‌های مکانی باقی‌مانده در \f[CB]$ARGS\&.positional\f[R]\&. .PP اگر این گزینه داده شود، تمام آرگومان‌های بعدی که در غیر این صورت به عنوان فایل ورودی تفسیر می‌شدند، در قالب یک آرایه در \f[CB]$ARGS\&.positional\f[R] جمع‌آوری می‌شوند\&. .PP برای نمونه: .IP .EX $ touch tmp\&.json && jaq \[aq]$ARGS\&.positional\[aq] tmp\&.json \-\-args foo \-nc bar \-\- baz \-j qux && rm tmp\&.json [\[dq]foo\[dq],\[dq]bar\[dq],\[dq]baz\[dq],\[dq]\-j\[dq],\[dq]qux\[dq]] .EE .PP توجه داشته باشید که در اینجا \f[CB]tmp\&.json\f[R] و \f[CB]\-nc\f[R] در آرایه جمع‌آوری \f[B]نمی‌شوند\f[R] — اولی به این دلیل که \f[B]قبل\f[R] از \f[CB]\-\-args\f[R] آمده است، و دومی به این دلیل که به عنوان فایل ورودی تفسیر نمی‌شده است\&. با این حال، \f[CB]\-j\f[R] در آرایه جمع‌آوری می‌شود زیرا بعد از \f[CB]\-\-\f[R] آمده است، که باعث می‌شود هر آرگومان بعد از آن به عنوان فایل ورودی تلقی شود\&. .SS "متفرقه (MISCELLANEA)" .SS \f[CB]\-e\f[R], \f[CB]\-\-exit\-status\f[R] .PP استفاده از آخرین مقدار خروجی به عنوان کد وضعیت خروج\&. .PP این گزینه امکان استفاده از کدهای خروج 1 و 4 را فراهم می‌کند که در حالت عادی استفاده نمی‌شوند\&. .PP دستور jaq از کدهای وضعیت خروج زیر استفاده می‌کند: .RS 2 .IP \[bu] 2 0: بدون خطا\&. .IP \[bu] 2 1: آخرین مقدار خروجی \f[CB]false\f[R] یا \f[CB]null\f[R] است\&. .IP \[bu] 2 2: خطای I/O یا CLI، مانند فایل پیدا نشد یا گزینه ناشناخته در CLI\&. .IP \[bu] 2 3: خطای تجزیه/کامپایل فیلتر\&. .IP \[bu] 2 4: فیلتر هیچ خروجی‌ای تولید نکرد\&. .IP \[bu] 2 5: هر خطای دیگر، مانند فراخوانی فیلتر \f[CB]error\f[R]\&. .RE .PP فیلترهای \f[CB]halt\f[R] و \f[CB]halt_error\f[R] می‌توانند برای خروج از jaq با کدهای خروج دلخواه استفاده شوند\&. .PP برای نمونه: .IP .EX $ jaq \-n empty; echo $? 0 $ jaq \-n false >/dev/null; echo $? 0 $ jaq \-en false >/dev/null; echo $? 1 $ jaq \&. does_not_exist\&.json 2>/dev/null; echo $? 2 $ jaq \-\-foo 2>/dev/null; echo $? 2 $ jaq \[aq]+\[aq] 2>/dev/null; echo $? 3 $ jaq \-en empty; echo $? 4 $ jaq \-n error 2>/dev/null; echo $? 5 $ jaq \-n \[aq]halt(9)\[aq]; echo $? 9 .EE .SS \f[CB]\-h\f[R], \f[CB]\-\-help\f[R] .PP چاپ خلاصه‌ای از گزینه‌های خط فرمان\&. .SS \f[CB]\-V\f[R], \f[CB]\-\-version\f[R] .PP چاپ نسخه jaq\&. .SS "پشتیبانی‌نشده (UNSUPPORTED)" .PP گزینه‌های خط فرمان زیر توسط \f[CB]jq\f[R] پشتیبانی می‌شوند، اما در jaq پشتیبانی نمی‌شوند: .RS 2 .IP \[bu] 2 \f[CB]\-\-ascii\-output\f[R], \f[CB]\-a\f[R] .IP \[bu] 2 \f[CB]\-\-unbuffered\f[R] .IP \[bu] 2 \f[CB]\-\-stream\f[R] .IP \[bu] 2 \f[CB]\-\-stream\-errors\f[R] .IP \[bu] 2 \f[CB]\-\-seq\f[R] .IP \[bu] 2 \f[CB]\-\-jsonargs\f[R] .RE .SH "زبان هسته (CORE LANGUAGE)" .PP زبان jq یک زبان برنامه‌نویسی تابعی، جریانی (streaming) و غیرحریص (lazy) است که در ابتدا توسط استیون دولان (Stephen Dolan) طراحی شد\&. زبان jq تورینگ\-کامل است و بنابراین می‌تواند برای نوشتن هر برنامه‌ای که در سایر زبان‌های برنامه‌نویسی قابل نگارش است به کار رود\&. برنامه‌های jq با چندین مفسر قابل اجرا هستند، از جمله \f[CB]jq\f[R]، \f[CB]gojq\f[R]، \f[CB]fq\f[R] و \f[CB]jaq\f[R]\&. .PP به برنامه‌ای که به زبان jq نوشته می‌شود، یک برنامه jq یا \f[I]فیلتر\f[R] گفته می‌شود\&. فیلتر تابعی است که یک مقدار ورودی دریافت کرده و جریانی از مقادیر خروجی را تولید می‌کند\&. طبق قرارداد، از \f[CB]f\f[R] و \f[CB]g\f[R] برای نشان دادن فیلترهای دلخواه استفاده می‌کنیم\&. .PP جریان مقادیر خروجی می‌تواند نامتناهی باشد؛ برای نمونه، فیلتر jq با دستور \f[CB]repeat(\[dq]Hi\[dq])\f[R] یک توالی نامتناهی از رشته‌های \f[CB]\[dq]Hi\[dq]\f[R] تولید می‌کند\&. .PP بخش‌های زیر تمامی فیلترها را با نحو توکار در jq مستند می‌کنند\&. مثال‌ها به صورت \f[CB]1 + 2, true or false \-\-> 3 true\f[R] نوشته شده‌اند که معادل است با: .IP .EX $ jaq \-n \[aq]1 + 2, true or false\[aq] 3 true .EE .PP یک فیلتر \f[B]اتمیک\f[R] (atomic) فیلتری است که یک عملگر دوتایی (binary operator) \f[I]نیست\f[R]\&. برای نمونه، فیلترهای \f[CB]\-1\f[R]، \f[CB]map(\&.+1)\f[R] و \f[CB]\&.[0]\f[R] همگی اتمیک هستند، در حالی که فیلترهای \f[CB]1 + 2\f[R]، \f[CB]explode | \&.[]\f[R] و \f[CB]\&.[0] += 1\f[R] غیراتمیک هستند\&. برای تبدیل یک فیلتر غیراتمیک \f[CB]f\f[R] به یک فیلتر اتمیک معادل، آن را درون پرانتز قرار دهید، یعنی \f[CB](f)\f[R]\&. .SS "مقادیر (VALUES)" .PP این بخش تمام مقادیر بالقوه‌ای را که فیلترهای jq می‌توانند پردازش کنند و نحوه تولید آن‌ها را فهرست می‌کند\&. .PP \f[I]سازگاری\f[R] .RS دستور jaq مجموعه مقادیری را که jq می‌تواند پردازش کند با رشته‌های بایتی و اشیاء دارای مقادیر کلید غیررشته‌ای گسترش می‌دهد\&. در حالی که jq مقادیر را به صورت پیش‌فرض به شکل JSON می‌خواند و می‌نویسد، دستور jaq مقادیر را به طور پیش‌فرض به صورت XJON می‌خواند و می‌نویسد، که یک توسعه از JSON است\&. بخش‌های مربوطه را برای نحوه سریال‌سازی مقادیر توسط jaq ببینید\&. .RE .SS \f[CB]null\f[R] .PP فیلتر \f[CB]null\f[R] مقدار \f[CB]null\f[R] را برمی‌گرداند\&. .PP مقدار \f[CB]null\f[R] به روش‌های گوناگون دیگری نیز قابل دستیابی است، مانند ایندکس کردن کلیدی که در آرایه یا شیء وجود ندارد؛ برای نمونه: \f[CB][] | \&.[0] \-\-> null\f[R] یا \f[CB]{} | \&.a \-\-> null\f[R]\&. .SS "بولی‌ها (Booleans)" .PP فیلترهای \f[CB]true\f[R] و \f[CB]false\f[R] مقادیر بولی \f[CB]true\f[R] و \f[CB]false\f[R] را برمی‌گردانند\&. بولی‌ها همچنین می‌توانند توسط عملیات‌های مقایسه تولید شوند؛ برای نمونه: \f[CB]0 == 0 \-\-> true\f[R] یا \f[CB][] == {} \-\-> false\f[R]\&. .PP هر مقدار jq را می‌توان به یک \f[B]مقدار بولی\f[R] نگاشت کرد؛ بدین صورت که \f[CB]null\f[R] و \f[CB]false\f[R] دارای مقدار بولی \f[CB]false\f[R] هستند و تمام مقادیر دیگر دارای مقدار بولی \f[CB]true\f[R] هستند\&. این ویژگی برای فیلترهایی مانند \f[CB]if\-then\-else\f[R] و \f[CB]//\f[R] دارای اهمیت است\&. .SS "اعداد (Numbers)" .PP اعداد فیلترهایی هستند که مقدار متناظر خود را برمی‌گردانند؛ برای نمونه: \f[CB]0 \-\-> 0\f[R]، \f[CB]3\&.14 \-\-> 3\&.14\f[R] و \f[CB]2\&.99e6 \-\-> 2\&.99e6\f[R]\&. اعداد منفی را می‌توان با اعمال عملگر نفی به یک عدد ساخت؛ برای نمونه: \f[CB]\-1 \-\-> \-1\f[R]\&. .PP به طور داخلی، jaq میان اعداد صحیح (integers)، اعداد ممیز شناور (floats) و اعداد ده‌دهی (decimals) تمایز قائل می‌شود: .RS 2 .IP \[bu] 2 یک عدد بدون نقطه (\f[CB]\&.\f[R]) و بدون توان (\f[CB]e\f[R]/\f[CB]E\f[R]) بدون از دست رفتن دقت به عنوان عدد صحیح ذخیره می‌شود\&. دستور jaq می‌تواند اعدادی با اندازه دلخواه و بزرگ را ذخیره و محاسبه کند؛ برای نمونه: \f[CB]340282366920938463463374607431768211456\f[R] (\f[CB]2^128\f[R])\&. .IP \[bu] 2 هر عدد غیرصحیح در ابتدا به صورت یک عدد ده‌دهی ذخیره می‌شود، که یک نمایش متنی از آن عدد است\&. این بدان معناست که jaq هر عددی را که با عبارت منظم فوق مطابقت داشته باشد، مانند \f[CB]1\&.0e500\f[R]، در صورتی که در یک فایل JSON یا فیلتر jq ظاهر شود، بدون افت دقت حفظ می‌کند\&. .IP \[bu] 2 هنگام انجام محاسبه با یک عدد ده‌دهی، دستور jaq آن را به صورت شفاف به یک عدد ممیز شناور ۶۴ بیتی \c .UR https://en.wikipedia.org/wiki/IEEE_754 IEEE\-754 .UE \c تبدیل می‌کند\&. برای نمونه، \f[CB]1\&.0e500 + 1 \-\-> Infinity\f[R]، زیرا jaq عدد \f[CB]1\&.0e500\f[R] را به نزدیک‌ترین عدد ممیز شناور که \f[CB]Infinity\f[R] است تبدیل می‌نماید\&. .RE .PP قوانین محاسباتی jaq به شرح زیر است: .RS 2 .IP \[bu] 2 مجموع، تفاضل، حاصلضرب و باقیمانده دو عدد صحیح، یک عدد صحیح است؛ برای نمونه: \f[CB]1 + 2 \-\-> 3\f[R]\&. .IP \[bu] 2 هر عملیات دیگر میان دو عدد حاصل ممیز شناور تولید می‌کند؛ برای نمونه: \f[CB]10 / 2 \-\-> 5\&.0\f[R] و \f[CB]1\&.0 + 2 \-\-> 3\&.0\f[R]\&. .RE .PP می‌توانید یک عدد صحیح را به ممیز شناور تبدیل کنید؛ برای نمونه با جمع کردن با 0.0، ضرب در 1.0 یا تقسیم بر 1\&. همچنین می‌توانید یک عدد ممیز شناور را با توابع \f[CB]round\f[R]، \f[CB]floor\f[R] یا \f[CB]ceil\f[R] به عدد صحیح تبدیل کنید؛ برای نمونه: \f[CB]1\&.2 | floor, round, ceil \-\-> 1 1 2\f[R]\&. .PP \f[I]سازگاری\f[R] .RS برنامه \f[CB]jq\f[R] برای تمام اعداد از ممیز شناور استفاده می‌کند، بدین معنی که تمایزی بین عدد صحیح و ممیز شناور قائل نمی‌شود\&. بسیاری از عملیات‌ها در jaq، مانند اندیس‌گذاری آرایه، بررسی می‌کنند که آیا اعداد ارائه‌شده واقعاً صحیح هستند یا خیر\&. انگیزه این کار، اجتناب از خطاهای گرد کردن است که می‌تواند به طور خاموش به نتایج نادرست منجر شود\&. برای نمونه: \f[CB][0, 1, 2] | \&.[1] \-\-> 1\f[R]، در حالی که \f[CB][0, 1, 2] | \&.[1\&.0000000000000001]\f[R] در jaq منجر به خطا می‌شود، بر خلاف \f[CB]jq\f[R] که مقدار \f[CB]1\f[R] می‌دهد\&. .PP افزون بر این، \f[CB]jq\f[R] مقدار NaN را به صورت \f[CB]null\f[R] چاپ می‌کند؛ برای نمونه \f[CB]nan | tojson\f[R] مقدار \f[CB]null\f[R] می‌دهد\&. در مقابل، jaq مقدار NaN را به عنوان \f[CB]NaN\f[R] چاپ می‌کند؛ برای نمونه \f[CB]nan | tojson \-\-> \[dq]NaN\[dq]\f[R]\&. بخش XJON را برای جزئیات ببینید\&. .RE .SS "رشته‌های متنی (Text strings)" .PP یک رشته متنی آرایه‌ای از بایت‌ها است که می‌تواند با نحو \f[CB]\[dq]\&.\&.\&.\[dq]\f[R] ساخته شود\&. در اینجا، \f[CB]\&.\&.\&.\f[R] ممکن است شامل هر کاراکتر UTF\-8 در محدوده \f[CB]U+0020\f[R] تا \f[CB]U+10FFFF\f[R] باشد، به استثنای \f[CB]\[aq]\[dq]\[aq]\f[R] و \f[CB]\[aq]\[rs]\[aq]\f[R]\&. برای نمونه: \f[CB]\[dq]Hello 東京!\[dq] \-\-> \[dq]Hello 東京!\[dq]\f[R]\&. .PP علاوه بر این، \f[CB]\&.\&.\&.\f[R] می‌تواند شامل توالی‌های گریز زیر باشد: .RS 2 .IP \[bu] 2 \f[CB]\[rs]b\f[R]، \f[CB]\[rs]f\f[R]، \f[CB]\[rs]n\f[R]، \f[CB]\[rs]r\f[R]، یا \f[CB]\[rs]t\f[R] .IP \[bu] 2 \f[CB]\[rs]\[dq]\f[R] یا \f[CB]\[rs]\[rs]\f[R] .IP \[bu] 2 \f[CB]\[rs]uHHHH\f[R] که در آن \f[CB]HHHH\f[R] یک عدد هگزادسیمال است .IP \[bu] 2 \f[CB]\[rs](f)\f[R] که در آن \f[CB]f\f[R] یک فیلتر jq است (\f[B]درون‌یابی رشته‌ای / string interpolation\f[R]) .RE .PP بیشتر کاراکترهای زیر \f[CB]U+0020\f[R] تنها از طریق توالی گریز یونیکد قابل تولید هستند؛ یعنی: \f[CB]\[dq]NUL = \[rs]u0000\[dq] \-\-> \[dq]NUL = \[rs]u0000\[dq]\f[R]\&. .PP یک رشته حاوی یک فیلتر درون‌یابی‌شده، مانند \f[CB]\[dq]\&.\&.\&.\[rs](f)\&.\&.\&.\[dq]\f[R]، معادل است با: \f[CB]\[dq]\&.\&.\&.\[dq] + (f | tostring) + \[dq]\&.\&.\&.\[dq]\f[R]\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB]\[dq]Hello \[rs](\[dq]Alice\[dq], \[dq]Bob\[dq]) 😀!\[rs]n\[dq] \-\-> \[dq]Hello Alice 😀!\[rs]n\[dq] \[dq]Hello Bob 😀!\[rs]n\[dq]\f[R] .IP \[bu] 2 \f[CB]41 | \[dq]The successor of \[rs](\&.) is \[rs](\&.+1)\&.\[dq] \-\-> \[dq]The successor of 41 is 42\&.\[dq]\f[R]\&. .RE .PP یک رشته را \f[B]شبه‌شناسه\f[R] (identifier\-like) می‌نامیم اگر با عبارت منظم \f[CB][a\-zA\-Z_][a\-zA\-Z_0\-9]*\f[R] مطابقت داشته باشد\&. .PP رشته‌ها می‌توانند دارای پیشوند \f[CB]@x\f[R] باشند که در آن \f[CB]x\f[R] یک شناسه است؛ مانند \f[CB]@uri\f[R]\&. در این صورت، فیلترهای رشته‌های درون‌یابی‌شده به جای \f[CB]tostring\f[R] از طریق \f[CB]@x\f[R] لوله‌کشی (pipe) می‌شوند، یعنی: \f[CB]@x \[dq]\&.\&.\&.\[rs](f)\&.\&.\&.\[dq]\f[R] معادل است با \f[CB]@x \[dq]\&.\&.\&.\[dq] + (f | @x) + @x \[dq]\&.\&.\&.\[dq]\f[R]\&. هنگامی که \f[CB]\[dq]\&.\&.\&.\[dq]\f[R] شامل هیچ فیلتر درون‌یابی‌شده‌ای نباشد، \f[CB]@x \[dq]\&.\&.\&.\[dq]\f[R] معادل با \f[CB]\[dq]\&.\&.\&.\[dq]\f[R] خواهد بود\&. برای نمونه: \f[CB]\[dq]\-[]?\[dq] | @uri \[dq]https://gedenkt\&.at/jaq/?q=\[rs](\&.)\[dq] \-\-> \[dq]https://gedenkt\&.at/jaq/?q=\-%5B%5D%3F\[dq]\f[R]\&. .SS "رشته‌های بایتی (Byte strings)" .PP یک رشته بایتی، آرایه‌ای از بایت‌ها است که به عنوان متن (UTF\-8) تفسیر \f[B]نمی‌شود\f[R]\&. این نوع رشته را می‌توان از یک رشته متنی از طریق فیلتر \f[CB]tobytes\f[R] تولید کرد؛ برای نمونه: \f[CB]\[dq]Hello, world! 🙂\[dq] | tobytes \-\-> b\[dq]Hello, world! \[rs]xf0\[rs]x9f\[rs]x99\[rs]x82\[dq]\f[R]\&. در حال حاضر هیچ نحو بومی مستقیمی در jaq برای ساخت رشته بایتی به صورت مستقیم وجود ندارد\&. .PP رشته‌های بایتی از چند جنبه با رشته‌های متنی متفاوت هستند؛ به ویژه اینکه ایندکس‌گذاری و برش‌زنی (slicing) آن‌ها در زمان ثابت صورت می‌گیرد\&. این ویژگی رشته‌های بایتی را برای نمونه جهت تجزیه قالب‌های باینری جذاب می‌کند\&. .PP به دلایل سازگاری، jaq هر دو نوع رشته‌های متنی و بایتی را به عنوان رشته در نظر می‌گیرد\&. بدین معنا که \f[CB]\[dq]Hello\[dq] | isstring and (tobytes | isstring) \-\-> true\f[R]\&. علاوه بر این، یک رشته متنی و یک رشته بایتی که حاوی بایت‌های معادل باشند، برابر تلقی می‌شوند؛ برای نمونه: \f[CB]\[dq]Hello\[dq] | \&. == tobytes \-\-> true\f[R]\&. .PP \f[I]سازگاری\f[R] .RS رشته‌های بایتی در \f[CB]jq\f[R] وجود ندارند؛ اما در \f[CB]fq\f[R] وجود دارند\&. .RE .SS "آرایه‌ها (Arrays)" .PP یک آرایه دنباله‌ای متناهی از مقادیر است\&. .PP یک آرایه خالی را می‌توان با فیلتر \f[CB][]\f[R] ساخت، که شکل خلاصه برای \f[CB][empty] \-\-> []\f[R] است\&. یک آرایه از مقادیر را می‌توان با نحو \f[CB][f]\f[R] ساخت، که در آن \f[CB]f\f[R] یک فیلتر است\&. فیلتر \f[CB][f]\f[R] ورودی خود را به \f[CB]f\f[R] پاس داده و آن را اجرا می‌کند، و آرایه‌ای شامل تمام خروجی‌های \f[CB]f\f[R] را بازمی‌گرداند\&. اگر \f[CB]f\f[R] خطایی صادر کند، \f[CB][f]\f[R] به جای آرایه آن خطا را برمی‌گرداند\&. .PP این نحو امکان ساخت آرایه‌هایی مانند \f[CB][1, 2, 3] \-\-> [1, 2, 3]\f[R] را فراهم می‌کند\&. در اینجا، \f[CB]1, 2, 3\f[R] صرفاً فیلتری است که سه عدد تولید می‌کند (بخش الحاق را ببینید)\&. هیچ نحو اختصاصی برای آرایه به صورت \f[CB][x1, \&.\&.\&., xn]\f[R] وجود ندارد\&. این بدان معنی است که می‌توانید از فیلترهای دلخواه در \f[CB][f]\f[R] استفاده کنید؛ برای نمونه: \f[CB][limit(3; repeat(0))] \-\-> [0, 0, 0]\f[R]\&. می‌توانید از ورودی داده‌شده به \f[CB][f]\f[R] در داخل \f[CB]f\f[R] استفاده کنید؛ برای نمونه، می‌توان فیلتر قبلی را به طور معادل چنین نوشت: \f[CB]{count: 3, elem: 0} | [limit(\&.count; repeat(\&.elem))] \-\-> [0, 0, 0]\f[R]\&. .SS "اشیاء (Objects)" .PP یک شیء نگاشتی از کلیدها به مقادیر است\&. .PP یک شیء خالی را می‌توان با فیلتر \f[CB]{}\f[R] ساخت\&. یک شیء با یک جفت کلید و مقدار را می‌توان با \f[CB]{(k): v}\f[R] ایجاد کرد، که در آن \f[CB]k\f[R] و \f[CB]v\f[R] هر دو فیلتر هستند\&. برای نمونه: \f[CB]{(\[dq]a\[dq]): 1} \-\-> { \[dq]a\[dq]: 1 }\f[R]\&. .PP اگر \f[CB]k\f[R] یک رشته مانند \f[CB]\[dq]a\[dq]\f[R] یا یک متغیر مانند \f[CB]$k\f[R] باشد، می‌توانید پرانتزها را حذف کنید؛ مانند \f[CB]{\[dq]a\[dq]: 1}\f[R] یا \f[CB]{$k: 1}\f[R]\&. اگر رشته شبه‌شناسه باشد، می‌توانید کوتیشن‌ها را نیز حذف کنید؛ مانند \f[CB]{a: 1}\f[R]\&. .PP برای ساخت یک شیء با چندین جفت کلید\-مقدار، می‌توانید چندین شیء را با هم جمع کنید؛ مانند: \f[CB]{(k1): v1} + \&.\&.\&. + {(kn): vn}\f[R]\&. می‌توانید این را به صورت فشرده‌تر چنین بنویسید: \f[CB]{(k1): v1, \&.\&.\&., (kn): vn}\f[R]\&. برای نمونه: \f[CB]{a: 1, b: 2} \-\-> { \[dq]a\[dq]: 1, \[dq]b\[dq]: 2 }\f[R]\&. .PP به جای \f[CB]{k: \&.k}\f[R] (ایندکس‌گذاری را ببینید)، می‌توانید به طور خلاصه بنویسید \f[CB]{k}\f[R]؛ برای نمونه: \f[CB]{a: 1, b: 2} | {a} \-\-> { \[dq]a\[dq]: 1 }\f[R]\&. همچنین به جای \f[CB]{k: $k}\f[R]، می‌توانید بنویسید \f[CB]{$k}\f[R]؛ برای نمونه: \f[CB]1 as $k | {$k} \-\-> { \[dq]k\[dq]: 1 }\f[R]\&. .PP فیلتر \f[CB]{(k): v}\f[R] معادل با \f[CB]k as $k | v as $v | {$k: $v}\f[R] است\&. این بدان معنی است که وقتی \f[CB]k\f[R] یا \f[CB]v\f[R] چندین مقدار خروجی تولید می‌کنند، یک شیء به ازای هر ترکیب خروجی تولید می‌شود؛ برای نمونه: \f[CB]{(\[dq]a\[dq], \[dq]b\[dq]): (1, 2)} \-\-> { \[dq]a\[dq]: 1 } { \[dq]a\[dq]: 2 } { \[dq]b\[dq]: 1 } { \[dq]b\[dq]: 2 }\f[R]\&. توجه داشته باشید که در اینجا لازم است \f[CB]1, 2\f[R] درون پرانتز قرار گیرد تا مشخص شود که کاما \f[CB],\f[R] یک جفت کلید\-مقدار جدید را آغاز نمی‌کند\&. .PP \f[I]سازگاری\f[R] .RS در jq، کلیدها باید رشته باشند، در حالی که در jaq، کلیدها می‌توانند مقادیر دلخواه باشند\&. از آنجا که در jaq کلیدهای شیء می‌توانند مقادیر دلخواه باشند، می‌توانید به عنوان نمونه بنویسید: .IP .EX {(0): 1, \[dq]2\[dq]: 3, ([4]): 5, ({}): 6} \-\-> { 0 : 1, \[dq]2\[dq]: 3, [4] : 5, {} : 6} .EE .PP توجه داشته باشید که در فیلتر jq، کلیدهای غیررشته‌ای باید درون پرانتز قرار گیرند، در حالی که در XJON نباید از پرانتز استفاده شود\&. .PP این دستور در \f[CB]jq\f[R] خطا می‌دهد\&. .RE .SS "عملگرهای مسیر (PATH OPERATORS)" .PP عملگرهای مسیر در jq بخش‌هایی از ورودی خود را بازیابی می‌کنند\&. .SS "ایندکس‌گذاری (\f[CB]\&.[x]\f[R])" .PP عملگر ایندکس‌گذاری \f[CB]\&.[x]\f[R] عنصر \f[CB]x\f[R]\-ام ورودی را برمی‌گرداند\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | \&.[1] \-\-> 2\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} | \&.[\[dq]a\[dq]] \-\-> 1\f[R] .RE .PP اگر هیچ عنصری در ایندکس \f[CB]x\f[R] در ورودی وجود نداشته باشد، این عملگر \f[CB]null\f[R] برمی‌گرداند\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | \&.[3] \-\-> null\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} | \&.[\[dq]c\[dq]] \-\-> null\f[R] .IP \[bu] 2 \f[CB]null | \&.[0] \-\-> null\f[R] .RE .PP این عملگر ورودی رشته بایتی را مانند آرایه‌ای از اعداد در محدوده 0 تا 256 تلقی می‌کند\&. برای نمونه: \f[CB]\[dq]@ABC\[dq] | tobytes | \&.[0] \-\-> 64\f[R]، زیرا کاراکتر \f[CB]\[aq]@\[aq]\f[R] در UTF\-8 به صورت بایت منفرد \f[CB]64\f[R] (\f[CB]0x40\f[R]) کدگذاری می‌شود\&. .PP برای رشته‌های شبه‌شناسه مانند \f[CB]name\f[R]، می‌توانید شکل خلاصه \f[CB]\&.name\f[R] را به جای \f[CB]\&.[\[dq]name\[dq]]\f[R] بنویسید؛ مانند: \f[CB]{a: 1} | \&.a \-\-> 1\f[R]\&. این کار همچنین برای رشته‌هایی که مشابه کلمات کلیدی رزروشده هستند کار می‌کند؛ مانند: \f[CB]{if: 1} | \&.if \-\-> 1\f[R]\&. .PP برای ورودی آرایه، می‌توانید از اعداد منفی نیز به عنوان ایندکس استفاده کنید، که به عنوان شمارش از انتهای آرایه تفسیر می‌شوند\&. برای نمونه: \f[CB][1, 2, 3] | \&.[\-1] \-\-> 3\f[R]\&. .PP اگر ورودی و ایندکس \f[CB]x\f[R] هر دو آرایه باشند، همان نتیجه \f[CB]indices(x)\f[R] بازگردانده می‌شود\&. برای نمونه: \f[CB][1, 2, 0, 1, 2] | \&.[[1, 2]] \-\-> [0, 3]\f[R]\&. .PP اگر ورودی این عملگر یک آرایه یا رشته باشد و ایندکس یک شیء باشد، این عملگر معادل با عملگر برش‌زنی (slicing) \f[CB]\&.[x\&.start : x\&.end]\f[R] است\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | \&.[{start: 1 }] \-\-> [2, 3]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | \&.[{ end: \-1}] \-\-> [1, 2]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | \&.[{start: 1, end: \-1}] \-\-> [2]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | \&.[{ }] \-\-> [1, 2, 3]\f[R] .RE .PP این عملگر در صورتی مقداری برمی‌گرداند که یکی از شرایط زیر برقرار باشد: .RS 2 .IP \[bu] 2 ورودی یک رشته یا آرایه باشد و ایندکس یک شیء باشد (برش‌زنی)، .IP \[bu] 2 ورودی یک رشته بایتی یا آرایه باشد و ایندکس یک عدد صحیح باشد، .IP \[bu] 2 ورودی و ایندکس هر دو آرایه باشند، یا .IP \[bu] 2 ورودی \f[CB]null\f[R] یا یک شیء باشد\&. .RE .PP در غیر این صورت، خطایی صادر می‌شود\&. .PP \f[I]سازگاری\f[R] .RS برنامه \f[CB]jq\f[R] اعداد ممیز شناور را به عنوان ایندکس آرایه می‌پذیرد؛ برای نمونه: \f[CB][1, 2] | \&.[1\&.5]\f[R] نتیجه \f[CB]2\f[R] می‌دهد\&. در jaq، ایندکس‌گذاری آرایه با یک عدد ممیز شناور منجر به خطا می‌شود\&. همین قاعده در مورد عملگر برش‌زنی در زیر نیز صدق می‌کند\&. .PP برنامه \f[CB]jq\f[R] هنگامی که ورودی یک رشته یا آرایه باشد و ایندکس شیئی بدون کلیدهای \f[CB]start\f[R] یا \f[CB]end\f[R] باشد با شکست مواجه می‌شود، در حالی که jaq با چنین شیئی مانند \f[CB]{start: null, end: null}\f[R] رفتار می‌کند؛ یعنی برشی از ابتدا تا انتها ایجاد می‌کند\&. .RE .SS "برش‌زنی (\f[CB]\&.[x:y]\f[R])" .PP عملگر برش‌زنی \f[CB]\&.[x:y]\f[R] برشی از یک رشته یا یک آرایه، از عنصر \f[CB]x\f[R]\-ام تا عنصر \f[CB]y\f[R]\-ام (بدون احتساب خود \f[CB]y\f[R]) تولید می‌کند\&. برای نمونه: \f[CB][1, 2, 3] | \&.[1:3] \-\-> [2, 3]\f[R] و \f[CB]\[dq]Hello World!\[dq] | \&.[6:11] \-\-> \[dq]World\[dq]\f[R]\&. .PP هنگام برش دادن یک رشته متنی، عنصر \f[CB]x\f[R]\-ام به \f[CB]x\f[R]\-امین \f[B]کاراکتر UTF\-8\f[R] اشاره دارد؛ برای نمونه: \f[CB]\[dq]老虎\[dq] | \&.[1:2] \-\-> \[dq]虎\[dq]\f[R]\&. از سوی دیگر، هنگام برش دادن یک رشته بایتی، عنصر \f[CB]x\f[R]\-ام به \f[CB]x\f[R]\-امین \f[B]بایت\f[R] اشاره دارد؛ برای نمونه: \f[CB]\[dq]Färber\[dq] | tobytes, \&. | \&.[2:] | [\&., length] \-\-> [b\[dq]\[rs]xa4rber\[dq], 5] [\[dq]rber\[dq], 4]\f[R]، زیرا حرف 'ä' دو بایت اما تنها یک کاراکتر اشغال می‌کند\&. .PP همانند عملگر ایندکس‌گذاری، عملگر برش‌زنی با ورودی رشته بایتی مانند آرایه‌ای از اعداد رفتار کرده و ایندکس‌های منفی را به صورت شمارش از انتها تفسیر می‌کند\&. .PP شکل خلاصه \f[CB]\&.[x:]\f[R] برشی از ایندکس \f[CB]x\f[R] تا انتها ایجاد می‌کند، و شکل خلاصه \f[CB]\&.[:y]\f[R] برشی از ابتدا تا ایندکس \f[CB]y\f[R] (غیرشامل) ایجاد می‌کند\&. هنگامی که \f[CB]x\f[R] برابر با \f[CB]null\f[R] باشد، به عنوان \f[CB]0\f[R] تفسیر می‌شود، و هنگامی که \f[CB]y\f[R] برابر با \f[CB]null\f[R] باشد، به عنوان \f[CB]length\f[R] تفسیر می‌شود\&. بدین معنا که \f[CB]\&.[x:]\f[R] معادل \f[CB]\&.[x:null]\f[R] و \f[CB]\&.[:y]\f[R] معادل \f[CB]\&.[null:y]\f[R] است\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB]\[dq]Hello World!\[dq] | \&.[ :5], \&.[6: ] \-\-> \[dq]Hello\[dq] \[dq]World!\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]Hello World!\[dq] | \&.[null:5], \&.[6:null] \-\-> \[dq]Hello\[dq] \[dq]World!\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]Hello World!\[dq] | \&.[null : null] \-\-> \[dq]Hello World!\[dq]\f[R] .RE .PP این عملگر در صورتی مقداری برمی‌گرداند که ورودی آن یک رشته یا یک آرایه باشد، و ایندکس‌های \f[CB]x\f[R] و \f[CB]y\f[R] آن یا \f[CB]null\f[R] یا عدد صحیح باشند\&. در غیر این صورت، خطا صادر می‌شود\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][] | try \&.[\[dq]a\[dq]:] catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .IP \[bu] 2 \f[CB]{} | try \&.[1:\-1] catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .RE .PP \f[I]سازگاری\f[R] .RS دستور jaq هنگام تلاش برای برش دادن \f[CB]null\f[R] با شکست مواجه می‌شود، یعنی: \f[CB]null | try \&.[1:] catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R]، در حالی که این دستور در \f[CB]jq\f[R] مقدار \f[CB]null\f[R] برمی‌گرداند\&. .RE .SS "پیمایش / تکرار (\f[CB]\&.[]\f[R])" .PP عملگر پیمایش \f[CB]\&.[]\f[R] هنگامی که آرایه \f[CB][v1, \&.\&.\&., vn]\f[R] یا شیء \f[CB]{k1: v1, \&.\&.\&., kn: vn}\f[R] به آن داده شود، تمام مقادیر \f[CB]v1 \&.\&.\&. vn\f[R] را تولید می‌کند\&. برای نمونه: \f[CB][1, 2, 3] | \&.[] \-\-> 1 2 3\f[R] و \f[CB]{a: 1, b: 2} | \&.[] \-\-> 1 2\f[R]\&. .SS "مسیرهای ترکیبی (Compound paths)" .PP می‌توانید هر تعداد عملگر مسیر را به یک فیلتر اتمیک الحاق کنید\&. به چنین توالی‌ای از عملگرهای مسیر، یک \f[I]مسیر ترکیبی\f[R] (compound path) گفته می‌شود\&. برای نمونه، می‌توانید \f[CB]explode\&.[]\f[R] را به عنوان شکل خلاصه \f[CB]explode | \&.[]\f[R] بنویسید\&. .PP اگر فیلتر اتمیک ابتدایی \f[CB]\&.\f[R] (همانی) باشد، می‌توانید آن را حذف کنید\&. برای نمونه، فیلترهای زیر همگی معادل یکدیگرند: .RS 2 .IP \[bu] 2 \f[CB]{a: [{b: 1}]} | \&. | \&.a | \&.[] | \&.b \-\-> 1\f[R] .IP \[bu] 2 \f[CB]{a: [{b: 1}]} | \&. \&.a \&.[] \&.b \-\-> 1\f[R] .IP \[bu] 2 \f[CB]{a: [{b: 1}]} | \&.a \&.[] \&.b \-\-> 1\f[R] .IP \[bu] 2 \f[CB]{a: [{b: 1}]} \&.a \&.[] \&.b \-\-> 1\f[R] .RE .PP می‌توانید \f[CB]\&.\f[R] ابتدایی عملگرهای مسیری را که به شکل \f[CB]\&.[\&.\&.\&.]\f[R] هستند حذف کنید، مگر اینکه آن عملگر مسیر در ابتدای مسیر ترکیبی باشد و فیلتر اتمیک ابتدایی \f[CB]\&.\f[R] حذف شده باشد\&. برای نمونه، فیلترهای زیر همگی معادل یکدیگرند: .RS 2 .IP \[bu] 2 \f[CB][[[1, 2, 3]]] | \&.[0] | \&.[] | \&.[:\-1] \-\-> [1, 2]\f[R] .IP \[bu] 2 \f[CB][[[1, 2, 3]]] | \&.[0] \&.[] \&.[:\-1] \-\-> [1, 2]\f[R] .IP \[bu] 2 \f[CB][[[1, 2, 3]]] | \&.[0] [] [:\-1] \-\-> [1, 2]\f[R] .IP \[bu] 2 \f[CB][[[1, 2, 3]]] [0] [] [:\-1] \-\-> [1, 2]\f[R] .RE .PP همچنین می‌توانید هر عملگر مسیر را در این بخش با یک \f[CB]?\f[R] خاتمه دهید، که خطاهای ناشی از آن عملگر را فرونشانی و پنهان می‌کند\&. برای نمونه، \f[CB]\&.[]\f[R] اگر ورودی نه آرایه باشد و نه شیء خطا می‌دهد، اما \f[CB]\&.[]?\f[R] این خطاها را مهار کرده و به جای آن هیچ خروجی‌ای تولید نمی‌کند\&. نمونه‌ها: .RS 2 .IP \[bu] 2 \f[CB][1, {a: 2 }, {a: 3 }] | \&.[]\&.a? \-\-> 2 3\f[R] .IP \[bu] 2 \f[CB][1, [2, 3 ], [4, 5 ]] | \&.[][]? \-\-> 2 3 4 5\f[R] .IP \[bu] 2 \f[CB]\ 1, {a: [2]}, {a: [3]} | \&.a?[] \-\-> 2 3\f[R] .RE .SS "عملگرهای بدون آرگومان (NULLARY)" .SS "همانی (\f[CB]\&.\f[R])" .PP فیلتر همانی \f[CB]\&.\f[R] ورودی خود را مستقیماً به خروجی منتقل می‌کند؛ برای نمونه: \f[CB]1 \-\-> 1\f[R]\&. .SS "بازگشت (\f[CB]\&.\&.\f[R])" .PP فیلتر بازگشتی \f[CB]\&.\&.\f[R] ورودی خود و تمام زیرمقادیر موجود در آن را تولید می‌کند\&. این فیلتر معادل با \f[CB]recurse\f[R] است\&. برای نمونه: \f[CB][1, [2]] | \&.\&. \-\-> [1, [2]] 1 [2] 2\f[R] و \f[CB]{a: {b: 1}} | \&.\&. \-\-> { \[dq]a\[dq]: { \[dq]b\[dq]: 1 } } { \[dq]b\[dq]: 1 } 1\f[R]\&. .SS "عملگرهای یکانی (UNARY)" .SS "نفی (\f[CB]\-\f[R])" .PP عملگر نفی \f[CB]\-f\f[R] ورودی را به فیلتر اتمیک \f[CB]f\f[R] می‌دهد و حاصل منفی خروجی‌های آن را برمی‌گرداند\&. برای نمونه: \f[CB]1 | \- \&. \-\-> \-1\f[R]\&. .SS "فرونشانی خطا (\f[CB]?\f[R])" .PP عملگر فرونشانی خطا \f[CB]f?\f[R] ورودی را به فیلتر اتمیک \f[CB]f\f[R] می‌دهد و خروجی‌های آن را برمی‌گرداند، اما هرگونه خطایی را که توسط \f[CB]f\f[R] پرتاب شود نادیده می‌گیرد\&. این عملگر معادل \f[CB]try f catch empty\f[R] است\&. برای نمونه: \f[CB]1 | \&.a? \-\-> \f[R] (هیچ خروجی‌ای تولید نمی‌شود)\&. .SS "عملگرهای دوتایی پیچیده (BINARY (COMPLEX))" .PP عملگرهای دوتایی پیچیده دو فیلتر را به عنوان آرگومان دریافت می‌کنند و می‌توانند تعداد خروجی‌های تولیدشده را تغییر دهند\&. .SS "ترکیب / لوله‌کشی (\f[CB]|\f[R])" .PP عملگر لوله‌کشی \f[CB]f | g\f[R] ورودی را به \f[CB]f\f[R] می‌دهد، و سپس هر خروجی \f[CB]f\f[R] را به نوبه خود به \f[CB]g\f[R] می‌دهد\&. این کار خروجی‌های \f[CB]g\f[R] را بازمی‌گرداند\&. برای نمونه: \f[CB][1, 2] | \&.[] | \&. + 1 \-\-> 2 3\f[R]\&. .SS "الحاق (\f[CB],\f[R])" .PP عملگر الحاق \f[CB]f, g\f[R] ورودی یکسان را به هر دو فیلتر \f[CB]f\f[R] و \f[CB]g\f[R] می‌دهد، و ابتدا خروجی‌های \f[CB]f\f[R] و سپس خروجی‌های \f[CB]g\f[R] را برمی‌گرداند\&. برای نمونه: \f[CB]1 | \&., \&. + 1 \-\-> 1 2\f[R]\&. .SS "پیوند متغیر (\f[CB]as $x |\f[R])" .PP دستور \f[CB]f as $x | g\f[R] فیلتر \f[CB]f\f[R] را روی ورودی اجرا می‌کند و به ازای هر خروجی \f[CB]f\f[R]، متغیر \f[CB]$x\f[R] را به آن مقدار مقید کرده و سپس \f[CB]g\f[R] را با همان ورودی اولیه اجرا می‌کند\&. برای نمونه: \f[CB]1 | (2, 3) as $x | \&. + $x \-\-> 3 4\f[R]\&. .SS "انتساب ساده (\f[CB]=\f[R])" .PP عملگر انتساب \f[CB]p = f\f[R] مقادیر ارجاع‌شده توسط مسیر \f[CB]p\f[R] را با خروجی‌های فیلتر \f[CB]f\f[R] جایگزین می‌کند\&. برای نمونه: \f[CB]{a: 1} | \&.a = 2 \-\-> { \[dq]a\[dq]: 2 }\f[R]\&. برای جزئیات بیشتر بخش انتساب‌ها را ببینید\&. .SS "انتساب به‌روزرسانی (\f[CB]|=\f[R])" .PP عملگر \f[CB]p |= f\f[R] مقادیر ارجاع‌شده توسط مسیر \f[CB]p\f[R] را با عبور دادن آن‌ها از فیلتر \f[CB]f\f[R] به‌روزرسانی می‌کند\&. برای نمونه: \f[CB]{a: 1} | \&.a |= \&. + 1 \-\-> { \[dq]a\[dq]: 2 }\f[R]\&. .SS "انتساب محاسباتی (\f[CB]+=\f[R]، \f[CB]\-=\f[R]، …)" .PP عملگرهای انتساب محاسباتی به شکل \f[CB]p o= f\f[R] خلاصه عبارت \f[CB]p |= \&. o f\f[R] هستند\&. عملگرهای معتبر عبارتند از: \f[CB]+=\f[R]، \f[CB]\-=\f[R]، \f[CB]*=\f[R]، \f[CB]/=\f[R]، \f[CB]%=\f[R] و \f[CB]//=\f[R]\&. برای نمونه: \f[CB]{a: 1} | \&.a += 2 \-\-> { \[dq]a\[dq]: 3 }\f[R]\&. .SS "تناوب (\f[CB]//\f[R])" .PP عملگر تناوب \f[CB]f // g\f[R] فیلتر \f[CB]f\f[R] را اجرا می‌کند\&. اگر \f[CB]f\f[R] حداقل یک مقدار با ارزش بولی \f[CB]true\f[R] (یعنی مقداری غیر از \f[CB]false\f[R] یا \f[CB]null\f[R]) تولید کند، تنها خروجی‌های معتبر \f[CB]f\f[R] بازگردانده می‌شوند\&. در غیر این صورت، خروجی‌های \f[CB]g\f[R] بازگردانده می‌شوند\&. برای نمونه: \f[CB]null // 1 \-\-> 1\f[R] و \f[CB]false // 2 \-\-> 2\f[R] و \f[CB]1 // 2 \-\-> 1\f[R]\&. .SS "منطق (\f[CB]or\f[R]، \f[CB]and\f[R])" .PP عملگرهای منطقی \f[CB]f or g\f[R] و \f[CB]f and g\f[R] محاسبات بولی را انجام می‌دهند\&. برای نمونه: \f[CB]true or false \-\-> true\f[R] و \f[CB]true and false \-\-> false\f[R]\&. .SS "عملگرهای دوتایی ساده (BINARY (SIMPLE))" .PP عملگرهای دوتایی ساده عملیات حسابی، مقایسه‌ای و تساوی را انجام می‌دهند\&. .SS "تساوی (\f[CB]==\f[R]، \f[CB]!=\f[R])" .PP عملگر \f[CB]f == g\f[R] بررسی می‌کند که آیا مقادیر تولیدشده توسط \f[CB]f\f[R] و \f[CB]g\f[R] برابر هستند یا خیر\&. عملگر \f[CB]f != g\f[R] برابری را نفی می‌کند\&. برای نمونه: \f[CB]1 == 1 \-\-> true\f[R] و \f[CB]1 != 2 \-\-> true\f[R]\&. .SS "ترتیب و مقایسه (\f[CB]<\f[R]، \f[CB]>\f[R]، \f[CB]<=\f[R]، \f[CB]>=\f[R])" .PP عملگرهای مقایسه‌ای ترتیب نسبی مقادیر را بررسی می‌کنند\&. ترتیب کلی انواع داده در jq به صورت زیر است: \f[CB]null < false < true < اعداد < رشته‌ها < آرایه‌ها < اشیاء\f[R]\&. برای نمونه: \f[CB]1 < 2 \-\-> true\f[R] و \f[CB]null < 0 \-\-> true\f[R] و \f[CB]true < \[dq]a\[dq] \-\-> true\f[R]\&. .SS "جمع و تفریق (\f[CB]+\f[R]، \f[CB]\-\f[R])" .PP عملگرهای \f[CB]+\f[R] و \f[CB]\-\f[R] برای عملیات حسابی روی اعداد، الحاق آرایه‌ها و رشته‌ها و ادغام اشیاء استفاده می‌شوند\&. برای نمونه: .RS 2 .IP \[bu] 2 اعداد: \f[CB]1 + 2 \-\-> 3\f[R] .IP \[bu] 2 آرایه‌ها: \f[CB][1] + [2] \-\-> [1, 2]\f[R] .IP \[bu] 2 رشته‌ها: \f[CB]\[dq]a\[dq] + \[dq]b\[dq] \-\-> \[dq]ab\[dq]\f[R] .IP \[bu] 2 اشیاء: \f[CB]{a: 1} + {b: 2} \-\-> { \[dq]a\[dq]: 1, \[dq]b\[dq]: 2 }\f[R] .RE .SS "ضرب و تقسیم (\f[CB]*\f[R]، \f[CB]/\f[R])" .PP عملگر \f[CB]*\f[R] برای ضرب اعداد و ادغام بازگشتی اشیاء استفاده می‌شود\&. عملگر \f[CB]/\f[R] برای تقسیم اعداد و تقسیم (split) رشته‌ها به کار می‌رود\&. برای نمونه: .RS 2 .IP \[bu] 2 ضرب اعداد: \f[CB]2 * 3 \-\-> 6\f[R] .IP \[bu] 2 تقسیم اعداد: \f[CB]6 / 2 \-\-> 3\&.0\f[R] .IP \[bu] 2 تقسیم رشته: \f[CB]\[dq]a,b\[dq] / \[dq],\[dq] \-\-> [\[dq]a\[dq], \[dq]b\[dq]]\f[R] .RE .SS "باقیمانده (\f[CB]%\f[R])" .PP عملگر \f[CB]f % g\f[R] باقیمانده تقسیم را برمی‌گرداند\&. برای نمونه: \f[CB]10 % 3 \-\-> 1\f[R]\&. .SS "کلمات کلیدی (KEYWORDS)" .SS "if\-then\-else" .PP عبارت شرطی \f[CB]if p then f else g end\f[R] ابتدا فیلتر شرطی \f[CB]p\f[R] را اجرا می‌کند\&. اگر حاصل دارای ارزش بولی \f[CB]true\f[R] باشد شاخه \f[CB]then\f[R]، و در غیر این صورت شاخه \f[CB]else\f[R] اجرا می‌شود\&. می‌توان از شاخه‌های اختیاری \f[CB]elif\f[R] نیز استفاده کرد\&. برای نمونه: \f[CB]if 1 > 0 then \[dq]yes\[dq] else \[dq]no\[dq] end \-\-> \[dq]yes\[dq]\f[R]\&. .SS "try\-catch" .PP عبارت \f[CB]try f catch g\f[R] فیلتر \f[CB]f\f[R] را اجرا می‌کند\&. اگر \f[CB]f\f[R] خطایی صادر کند، خطا متوقف شده و شاخه \f[CB]catch\f[R] با پیام خطا به عنوان ورودی اجرا می‌شود\&. بخش \f[CB]catch\f[R] اختیاری است (که در صورت حذف، خطا را نادیده می‌گیرد)\&. برای نمونه: \f[CB]try error(\[dq]oops\[dq]) catch \&. \-\-> \[dq]oops\[dq]\f[R]\&. .SS "label\-break" .PP ساختار \f[CB]label $out | ... break $out ...\f[R] امکان خروج زودهنگام از حلقه‌ها و جریان‌های پردازش را فراهم می‌کند\&. برای نمونه: \f[CB]label $out | 1, 2, break $out, 3 \-\-> 1 2\f[R]\&. .SS "reduce / foreach" .PP عبارت \f[CB]reduce f as $x (init; update)\f[R] روی تمام مقادیر تولیدشده توسط \f[CB]f\f[R] پیمایش می‌کند و حالت را با مقدار اولیه \f[CB]init\f[R] مقداردهی کرده و با هر عنصر با \f[CB]update\f[R] به‌روزرسانی می‌نماید، و در نهایت فقط حالت پایانی را برمی‌گرداند\&. عبارت \f[CB]foreach f as $x (init; update; extract)\f[R] مشابه است، اما حالت‌های میانی را نیز استخراج و تولید می‌کند\&. برای نمونه: \f[CB]reduce (1, 2, 3) as $x (0; \&. + $x) \-\-> 6\f[R]\&. .SS "def" .PP کلمه کلیدی \f[CB]def\f[R] برای تعریف توابع سفارشی به کار می‌رود\&. نحو کلی آن به صورت \f[CB]def name(args): body;\f[R] است\&. برای نمونه: \f[CB]def add_one: \&. + 1; 5 | add_one \-\-> 6\f[R]\&. .SH "کتابخانه استاندارد (STANDARD LIBRARY)" .PP این بخش تمامی فیلترهای نام‌گذاری‌شده‌ای را که به طور پیش‌فرض در هر ماژول jq در دسترس هستند فهرست می‌کند\&. این فیلترها به عنوان «توابع توکار» (builtins) نیز شناخته می‌شوند\&. .SS "توابع پایه (BASIC)" .SS \f[CB]error\f[R], \f[CB]error(f)\f[R] .PP فیلتر \f[CB]error(f)\f[R] به ازای هر خروجی \f[CB]f\f[R] خطایی صادر می‌کند که خروجی به عنوان بار پیام خطا قرار می‌گیرد\&. فیلتر \f[CB]error\f[R] معادل با \f[CB]error(\&.)\f[R] است\&. همچنین امکان استفاده از \f[CB]error(f)\f[R] در سمت چپ انتساب‌ها نیز وجود دارد\&. .PP مثال‌ها: .RS 2 .IP \[bu] 2 \f[CB]error(empty) \-\->\f[R] (no output) .IP \[bu] 2 \f[CB]try error(41) catch (\&. + 1) \-\-> 42\f[R] .IP \[bu] 2 \f[CB]try (41 | error ) catch (\&. + 1) \-\-> 42\f[R] .IP \[bu] 2 \f[CB]try (error(41) = 1) catch (\&. + 1) \-\-> 42\f[R] .RE .SS \f[CB]length\f[R] .PP خروجی فیلتر \f[CB]length\f[R] به نوع ورودی آن بستگی دارد: .RS 2 .IP \[bu] 2 مقدار \f[CB]null\f[R]: برابر \f[CB]0\f[R]، یعنی \f[CB]null | length \-\-> 0\f[R] .IP \[bu] 2 بولی: خطا، یعنی \f[CB]true | try length catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .IP \[bu] 2 عدد: قدر مطلق عدد، یعنی \f[CB]\-1, 1 | length \-\-> 1 1\f[R] .IP \[bu] 2 رشته متنی: تعداد کاراکترها، یعنی \f[CB]\[dq]ゼノギアス\[dq] | length \-\-> 5\f[R] .IP \[bu] 2 رشته بایتی: تعداد بایت‌ها، یعنی \f[CB]\[dq]ゼノギアス\[dq] | tobytes | length \-\-> 15\f[R] .IP \[bu] 2 آرایه: تعداد مقادیر، یعنی \f[CB][1, [2, 3], 4] | length \-\-> 3\f[R] .IP \[bu] 2 شیء: تعداد جفت‌های کلید\-مقدار، یعنی \f[CB]{a: 0, b: 1} | length \-\-> 2\f[R] .RE .SS \f[CB]keys\f[R], \f[CB]keys_unsorted\f[R] .PP فیلتر \f[CB]keys_unsorted\f[R] آرایه‌ای تولید می‌کند که در صورت شیء بودن ورودی حاوی تمام کلیدها و در صورت آرایه بودن ورودی حاوی تمام ایندکس‌ها است\&. فیلتر \f[CB]keys\f[R] معادل با \f[CB]keys_unsorted | sort\f[R] است\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB]{c: 1, b: 2, a: 1} | keys_unsorted \-\-> [\[dq]c\[dq], \[dq]b\[dq], \[dq]a\[dq]]\f[R] .IP \[bu] 2 \f[CB]{c: 1, b: 2, a: 1} | keys \-\-> [\[dq]a\[dq], \[dq]b\[dq], \[dq]c\[dq]]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | keys_unsorted \-\-> [0, 1, 2]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | keys \-\-> [0, 1, 2]\f[R] .RE .SS \f[CB]to_entries\f[R], \f[CB]from_entries\f[R], \f[CB]with_entries(f)\f[R] .PP فیلتر \f[CB]to_entries\f[R] یک آرایه یا یک شیء را به عنوان ورودی دریافت می‌کند\&. آن را به آرایه‌ای از اشیاء به شکل \f[CB]{key: k, value: v}\f[R] تبدیل می‌کند، به گونه‌ای که \f[CB]\&.[k]\f[R] روی ورودی اصلی مقدار \f[CB]v\f[R] را می‌دهد\&. For example: .RS 2 .IP \[bu] 2 \f[CB][ 1, 2] | to_entries \-\-> [{\[dq]key\[dq]: 0 , \[dq]value\[dq]: 1}, {\[dq]key\[dq]: 1 , \[dq]value\[dq]: 2}]\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} | to_entries \-\-> [{\[dq]key\[dq]: \[dq]a\[dq], \[dq]value\[dq]: 1}, {\[dq]key\[dq]: \[dq]b\[dq], \[dq]value\[dq]: 2}]\f[R] .RE .PP The filter \f[CB]from_entries\f[R] constructs an object from an array of entries as given by \f[CB]to_entries\f[R]\&. For example, \f[CB]{a: 1, b: 2} | to_entries | from_entries \-\-> {\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\f[R]\&. .PP The filter \f[CB]with_entries(f)\f[R] is equivalent to \f[CB]to_entries | map(f) | from_entries\f[R]\&. For example, \f[CB]{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2} | with_entries(\&.key |= ascii_upcase) \-\-> {\[dq]A\[dq]: 1, \[dq]B\[dq]: 2}\f[R] .SS "مصرف‌کنندگان جریان (STREAM CONSUMERS)" .SS \f[CB]first\f[R], \f[CB]first(f)\f[R], \f[CB]last\f[R], \f[CB]last(f)\f[R] .PP The filter \f[CB]first(f)\f[R] yields the first output of \f[CB]f\f[R] if there is one, else nothing\&. For example, \f[CB]first(1, 2, 3) \-\-> 1\f[R] and \f[CB]first(empty) \-\->\f[R] (no output)\&. .PP This filter stops evaluating \f[CB]f\f[R] after the first output, meaning that it yields an output even if \f[CB]f\f[R] yields infinitely many outputs\&. For example, \f[CB]first(repeat(0)) \-\-> 0\f[R] and \f[CB]first(1, def f: f; f) \-\-> 1\f[R]\&. .PP Similarly, \f[CB]last(f)\f[R] yields the last output of \f[CB]f\f[R] if there is one, else nothing\&. If \f[CB]f\f[R] yields an error, then the first error of \f[CB]f\f[R] is yielded\&. For example, \f[CB]last(1, 2, 3) \-\-> 3\f[R], \f[CB]last(empty) \-\->\f[R] (no output), and \f[CB]try last(1, error(\[dq]fail\[dq]), 3) catch \&. \-\-> \[dq]fail\[dq]\f[R]\&. .PP The filters \f[CB]first\f[R] and \f[CB]last\f[R] are short forms for \f[CB]first(\&.[])\f[R] and \f[CB]last(\&.[])\f[R], respectively\&. You can use them to retrieve the first/last element of an array, such as \f[CB][1, 2, 3] | first, last \-\-> 1 3\f[R]\&. .SS \f[CB]limit($n; f)\f[R] .PP The filter \f[CB]limit($n; f)\f[R] yields the first \f[CB]$n\f[R] outputs of \f[CB]f\f[R]\&. If \f[CB]$n <= 0\f[R], it yields no outputs\&. For example: .RS 2 .IP \[bu] 2 \f[CB]limit( 3; 1, 2 ) \-\-> 1 2\f[R] .IP \[bu] 2 \f[CB]limit( 3; 1, 2, 3, 4) \-\-> 1 2 3\f[R] .IP \[bu] 2 \f[CB]limit(\-1; 1, 2 ) \-\->\f[R] (no output) .RE .PP \f[I]سازگاری\f[R] .RS When \f[CB]$n < 0\f[R], \f[CB]jq\f[R] yields an error instead\&. .RE .SS \f[CB]skip($n; f)\f[R] .PP The filter \f[CB]skip($n; f)\f[R] yields all outputs after the first \f[CB]$n\f[R] outputs of \f[CB]f\f[R]\&. If \f[CB]$n <= 0\f[R], it yields all outputs of \f[CB]f\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]skip( 3; 1, 2 ) \-\->\f[R] (no output) .IP \[bu] 2 \f[CB]skip( 1; 1, 2, 3, 4) \-\-> 2 3 4\f[R] .IP \[bu] 2 \f[CB]skip(\-1; 1, 2 ) \-\-> 1 2\f[R] .RE .SS \f[CB]nth($i)\f[R], \f[CB]nth($i; f)\f[R] .PP The filter \f[CB]nth($i; f)\f[R] yields the \f[CB]$i\f[R]\-th output of \f[CB]f\f[R]\&. If \f[CB]f\f[R] yields less than \f[CB]$i\f[R] outputs, then this filter yields no output\&. For example: .RS 2 .IP \[bu] 2 \f[CB]nth(0; 1, 2, 3) \-\-> 1\f[R] .IP \[bu] 2 \f[CB]nth(2; 1, 2, 3) \-\-> 3\f[R] .IP \[bu] 2 \f[CB]nth(3; 1, 2, 3) \-\->\f[R] (no output) .RE .PP The filter \f[CB]nth($i)\f[R] is a short form for \f[CB]\&.[$i]\f[R]; e\&.g\&. \f[CB][1, 2, 3] | nth(0) \-\-> 1\f[R]\&. .SS \f[CB]isempty(f)\f[R] .PP فیلتر \f[CB]isempty(f)\f[R] در صورتی که \f[CB]f\f[R] هیچ خروجی‌ای تولید نکند \f[CB]true\f[R] و در غیر این صورت \f[CB]false\f[R] برمی‌گرداند\&. If the first output of \f[CB]f\f[R] is an error, \f[CB]isempty(f)\f[R] yields that error instead\&. For example: .RS 2 .IP \[bu] 2 \f[CB]isempty( empty) \-\-> true\f[R] .IP \[bu] 2 \f[CB]isempty(1, 2) \-\-> false\f[R] .IP \[bu] 2 \f[CB]isempty(1, error) \-\-> false\f[R] .IP \[bu] 2 \f[CB]try isempty(error, 1) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .RE .SS \f[CB]any\f[R], \f[CB]any(p)\f[R], \f[CB]any(f; p)\f[R] .PP The filter \f[CB]any(f; p)\f[R] yields \f[CB]true\f[R] if any output of \f[CB]f | p\f[R] has the boolean value \f[CB]true\f[R], else \f[CB]false\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]any(0, 1, 2; \&. == 42) \-\-> false\f[R] .IP \[bu] 2 \f[CB]any(0, 1, 2; \&. == 42, \&. == 2) \-\-> true\f[R] .RE .PP The filters \f[CB]any(p)\f[R] and \f[CB]any\f[R] are short forms of \f[CB]any(\&.[]; p)\f[R] and \f[CB]any(\&.)\f[R], respectively\&. For example: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | any(\&. % 2 == 0) \-\-> true\f[R] .IP \[bu] 2 \f[CB][false, true] | any \-\-> true\f[R] .RE .SS \f[CB]all\f[R], \f[CB]all(p)\f[R], \f[CB]all(f; p)\f[R] .PP The filter \f[CB]all(f; p)\f[R] yields \f[CB]true\f[R] if all outputs of \f[CB]f | p\f[R] have the boolean value \f[CB]true\f[R], else \f[CB]false\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]all(0, 1, 2; \&. > 0) \-\-> false\f[R] .IP \[bu] 2 \f[CB]all(0, 1, 2; \&. >= 0) \-\-> true\f[R] .RE .PP The filters \f[CB]all(p)\f[R] and \f[CB]all\f[R] are defined analogously to \f[CB]any(p)\f[R] and \f[CB]any\f[R]\&. .SS \f[CB]add\f[R], \f[CB]add(f)\f[R] .PP The filter \f[CB]add(f)\f[R] yields the sum of all elements yielded by \f[CB]f\f[R], or \f[CB]null\f[R] if \f[CB]f\f[R] yields no outputs\&. For example: .RS 2 .IP \[bu] 2 \f[CB]add(1, 2, 3) \-\-> 6\f[R] .IP \[bu] 2 \f[CB]add(empty) \-\-> null\f[R] .RE .PP The filter \f[CB]add\f[R] is a short form of \f[CB]add(\&.[])\f[R]\&. You can use it to add all values of an array or object: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | add \-\-> 6\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} | add \-\-> 3\f[R] .RE .SS "تولیدکنندگان جریان (STREAM GENERATORS)" .SS \f[CB]empty\f[R] .PP The filter \f[CB]empty\f[R] yields no output\&. .SS \f[CB]range($upto)\f[R], \f[CB]range($from; $upto)\f[R], \f[CB]range($from; $upto; $step)\f[R] .PP The filter \f[CB]range($from; $upto; $step)\f[R] adds \f[CB]$step\f[R] to \f[CB]$from\f[R] until it exceeds \f[CB]$upto\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]range(1; 9; 2) \-\-> 1 3 5 7\f[R] .IP \[bu] 2 \f[CB]range(1; 10; 2) \-\-> 1 3 5 7 9\f[R] .IP \[bu] 2 \f[CB]range(9; 1; \-2) \-\-> 9 7 5 3\f[R] .IP \[bu] 2 \f[CB]range(9; 0; \-2) \-\-> 9 7 5 3 1\f[R] .RE .PP The filter \f[CB]range($from; $upto)\f[R] is a short form of \f[CB]range($from; $upto; 1)\f[R] and the filter \f[CB]range($upto)\f[R] is a short form of \f[CB]range(0; $upto)\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]range(5) \-\-> 0 1 2 3 4\f[R] .IP \[bu] 2 \f[CB]range(2; 5) \-\-> 2 3 4\f[R] .RE .PP \f[I]سازگاری\f[R] .RS In \f[CB]jq\f[R], \f[CB]range/1\f[R] and \f[CB]range/2\f[R] are more restrictive versions of \f[CB]range/3\f[R] that prohibit non\-numeric arguments\&. .RE .SS \f[CB]recurse\f[R], \f[CB]recurse(f)\f[R] .PP The filter \f[CB]recurse(f)\f[R] is equivalent to \f[CB]\&., (f | recurse(f))\f[R]\&. It first outputs its input, then runs \f[CB]f\f[R] and \f[CB]recurse(f)\f[R] on its outputs\&. This is useful to create infinite sequences\&. You can create a finite sequence by having \f[CB]f\f[R] return \f[CB]empty\f[R], e\&.g\&. via \f[CB]select\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]0 | limit(5; recurse(\&.+1)) \-\-> 0 1 2 3 4\f[R] .IP \[bu] 2 \f[CB]0 | recurse(\&.+1 | select(\&. < 5)) \-\-> 0 1 2 3 4\f[R] .RE .PP The filter \f[CB]recurse(f; p)\f[R] is equivalent to \f[CB]recurse(f | select(p))\f[R]\&. That means that it recurses only on outputs of \f[CB]f\f[R] for which \f[CB]p\f[R] yields a \f[CB]true\f[R] output\&. For example: .RS 2 .IP \[bu] 2 \f[CB]0 | recurse(\&.+1; \&. < 5) \-\-> 0 1 2 3 4\f[R] .RE .PP The filter \f[CB]recurse\f[R] is a short form for \f[CB]recurse(\&.[]?)\f[R]\&. It returns all values recursively contained in the input, e\&.g\&. \f[CB][1, [2], {a: 3}] | recurse \-\-> [1, [2], {\[dq]a\[dq]: 3}] 1 [2] 2 {\[dq]a\[dq]:3} 3\f[R]\&. It yields the same outputs as \f[CB]\&.\&.\f[R] (recursion)\&. .SS \f[CB]repeat(f)\f[R] .PP The filter \f[CB]repeat(f)\f[R] runs \f[CB]f\f[R] and yields its outputs over and over again\&. For example, \f[CB]2 | limit(7; repeat(1, \&., 3)) \-\-> 1 2 3 1 2 3 1\f[R]\&. .SS \f[CB]while(p; f)\f[R], \f[CB]until(p; f)\f[R] .PP The filter \f[CB]while(p; f)\f[R] yields its input and applies \f[CB]f\f[R] to it, while \f[CB]p\f[R] returns true\&. .PP The filter \f[CB]until(p; f)\f[R] applies \f[CB]f\f[R] to its input until \f[CB]p\f[R] returns true, at which point the filter returns its input\&. .PP Examples: .RS 2 .IP \[bu] 2 \f[CB]0 | while(\&. <= 3; \&. + 1) \-\-> 0 1 2 3\f[R] .IP \[bu] 2 \f[CB]0 | until(\&. >= 3; \&. + 1) \-\-> 3\f[R] .RE .SS "انتخاب و فیلترسازی (SELECTION)" .PP The filters in this section classify their inputs or output them selectively\&. .SS \f[CB]select(p)\f[R] .PP The filter \f[CB]select(p)\f[R] yields its input for each true output of \f[CB]p\f[R]\&. For example, \f[CB](0, 1, \-1, 2, \-2) | select(\&. >= 0) \-\-> 0 1 2\f[R]\&. .SS \f[CB]nulls\f[R], \f[CB]booleans\f[R], \f[CB]numbers\f[R], \f[CB]strings\f[R], \f[CB]arrays\f[R], \f[CB]objects\f[R] .PP Any of these filters yields its input if it is of the given type, else nothing\&. For example: .RS 2 .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | nulls \-\-> null\f[R] .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | booleans \-\-> true\f[R] .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | numbers \-\-> 0\f[R] .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | strings \-\-> \[dq]Hi!\[dq]\f[R] .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | arrays \-\-> [1, 2]\f[R] .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | objects \-\-> {\[dq]a\[dq]: 1}\f[R] .RE .SS \f[CB]isboolean\f[R], \f[CB]isnumber\f[R], \f[CB]isstring\f[R], \f[CB]isarray\f[R], \f[CB]isobject\f[R] .PP For every filter in this section, like \f[CB]isboolean\f[R], …, \f[CB]isobject\f[R], there is a corresponding filter in the previous section like, \f[CB]booleans\f[R], …, \f[CB]objects\f[R]\&. Any of these filters yields \f[CB]true\f[R] if its corresponding filter in the previous section yields some output, else \f[CB]false\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]null | isboolean \-\-> false\f[R], because \f[CB]null | booleans \-\->\f[R] (no output)\&. .IP \[bu] 2 \f[CB]true | isboolean \-\-> true \f[R], because \f[CB]true | booleans \-\-> true\f[R]\&. .RE .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] does not implement these filters\&. .RE .SS \f[CB]normals\f[R], \f[CB]finites\f[R] .PP These filters return its input if \f[CB]isnormal\f[R] or \f[CB]isfinite\f[R] is \f[CB]true\f[R], respectively, else \f[CB]false\f[R]\&. .SS \f[CB]values\f[R], \f[CB]iterables\f[R], \f[CB]scalars\f[R] .PP The filter \f[CB]values\f[R] yields its input if it is \f[B]not\f[R] \f[CB]null\f[R], else nothing\&. .PP If a value is either an array or an object, it is said to be \f[B]iterable\f[R]; otherwise, it is said to be \f[B]scalar\f[R]\&. (The iteration filter \f[CB]\&.[]\f[R] succeeds on any iterable value, whereas it fails on any scalar\&.) .PP The filters \f[CB]iterables\f[R] and \f[CB]scalars\f[R] yield their input if it is iterable or scalar, respectively, else nothing\&. .PP Examples: .RS 2 .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | values \-\-> true 0 \[dq]Hi!\[dq] [1, 2] {\[dq]a\[dq]: 1}\f[R] .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | scalars \-\-> null true 0 \[dq]Hi!\[dq]\f[R] .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi!\[dq], [1, 2], {a: 1} | iterables \-\-> [1, 2] {\[dq]a\[dq]: 1}\f[R] .RE .SS \f[CB]isnan\f[R], \f[CB]isinfinite\f[R], \f[CB]isfinite\f[R], \f[CB]isnormal\f[R] .PP The filter \f[CB]isnan\f[R] yields \f[CB]true\f[R] if its input is \f[CB]NaN\f[R], else \f[CB]false\f[R]\&. Note that it is \f[B]not\f[R] equivalent to \f[CB]\&. == nan\f[R], because \f[CB]nan\f[R] is not equal to itself; see equality\&. .PP The filter \f[CB]isinfinite\f[R] yields \f[CB]true\f[R] if its input is either \f[CB]Infinity\f[R] or \f[CB]\-Infinity\f[R], else \f[CB]false\f[R]\&. .PP The filter \f[CB]isfinite\f[R] yields \f[CB]true\f[R] if its input is a number that is not infinite, else \f[CB]false\f[R]\&. .PP The filter \f[CB]isnormal\f[R] yields \f[CB]true\f[R] if its input is a number that is neither \f[CB]0\f[R], \f[CB]NaN\f[R], nor infinite\&. .PP Examples: .RS 2 .IP \[bu] 2 \f[CB]nan | isnan, isinfinite, isfinite, isnormal \-\-> true false true false\f[R] .IP \[bu] 2 \f[CB]infinite | isnan, isinfinite, isfinite, isnormal \-\-> false true false false\f[R] .IP \[bu] 2 \f[CB]0 | isnan, isinfinite, isfinite, isnormal \-\-> false false true false\f[R] .IP \[bu] 2 \f[CB]1 | isnan, isinfinite, isfinite, isnormal \-\-> false false true true\f[R] .RE .SS \f[CB]type\f[R] .PP The filter \f[CB]type\f[R] returns the type of its input value as string\&. For example: .RS 2 .IP \[bu] 2 \f[CB]null | type \-\-> \[dq]null\[dq]\f[R] .IP \[bu] 2 \f[CB]false | type \-\-> \[dq]boolean\[dq]\f[R] .IP \[bu] 2 \f[CB]0 | type \-\-> \[dq]number\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]foo\[dq] | type \-\-> \[dq]string\[dq]\f[R] .IP \[bu] 2 \f[CB][1] | type \-\-> \[dq]array\[dq]\f[R] .IP \[bu] 2 \f[CB]{} | type \-\-> \[dq]object\[dq]\f[R] .RE .PP Note that both text strings and byte strings both have the same type \f[CB]\[dq]string\[dq]\f[R]\&. .SS "عضویت و جستجو (MEMBERSHIP)" .SS \f[CB]contains($x)\f[R], \f[CB]inside($x)\f[R] .PP The filter \f[CB]contains($x)\f[R] yields \f[CB]true\f[R] if any of the following conditions holds, else \f[CB]false\f[R]\&. .RS 2 .IP \[bu] 2 The input is a string and \f[CB]$x\f[R] is a substring of it\&. .IP \[bu] 2 The input is an array, \f[CB]$x\f[R] is an array, and for every value \f[CB]v\f[R] in \f[CB]$x\f[R], there is some value in the input that \f[CB]contains(v)\f[R]\&. .IP \[bu] 2 The input is an object, \f[CB]$x\f[R] is an object, and for every key\-value pair \f[CB]{k: v}\f[R] in \f[CB]$x\f[R], there is a value for the key \f[CB]k\f[R] in the input that \f[CB]contains(v)\f[R]\&. .IP \[bu] 2 The input is \f[CB]null\f[R], boolean, or a number, and \f[CB]$x\f[R] is equal to the input\&. .RE .PP Examples: .RS 2 .IP \[bu] 2 \f[CB]\[dq]Hello, world!\[dq] | contains(\[dq]world\[dq]) \-\-> true\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | contains([1, 3]) \-\-> true\f[R] .IP \[bu] 2 \f[CB][[1, 2], 3] | contains([3, [1]]) \-\-> true\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} | contains({a: 1}) \-\-> true\f[R] .IP \[bu] 2 \f[CB]{a: [1, 2]} | contains({a: [1]}) \-\-> true\f[R] .IP \[bu] 2 \f[CB]0 | contains(0) \-\-> true\f[R] .RE .PP The filter \f[CB]inside($x)\f[R] is a flipped version of \f[CB]contains\f[R]\&. For example, \f[CB]\[dq]world\[dq] | inside(\[dq]Hello, world\[dq]) \-\-> true\f[R]\&. .SS \f[CB]indices($x)\f[R] .PP The filter \f[CB]indices($x)\f[R] yields the following: .RS 2 .IP \[bu] 2 If the input and \f[CB]$x\f[R] are either both strings or both arrays, then it yields the indices \f[CB]i\f[R] for which \f[CB]\&.[i:][:$x | length] == $x\f[R]; e\&.g\&. \f[CB]\[dq]Alice, Bob, and Carol\[dq] | indices(\[dq], \[dq]) \-\-> [5, 10]\f[R] and \f[CB][0, 1, 2, 3, 1, 2, 3] | indices([1, 2]) \-\-> [1, 4]\f[R]\&. .IP \[bu] 2 If the input is an array and \f[CB]$x\f[R] is not an array, then it yields the indices \f[CB]i\f[R] for which \f[CB]\&.[i] == $x\f[R]; e\&.g\&. \f[CB][0, 1, 2, 3, 1, 2, 3] | indices(1) \-\-> [1, 4]\f[R]\&. .IP \[bu] 2 Otherwise, it yields an error\&. .RE .PP This means that \f[CB][[1, 2], 3] | indices([1, 2]) \-\-> []\f[R], because the input array has neither \f[CB]1\f[R] nor \f[CB]2\f[R], just \f[CB][1, 2]\f[R] and \f[CB]3\f[R]\&. .SS \f[CB]index($x)\f[R], \f[CB]rindex($x)\f[R] .PP The filters \f[CB]index($x)\f[R] and \f[CB]rindex($x)\f[R] are shorthand for \f[CB]indices($x) | first\f[R] and \f[CB]indices($x) | last\f[R], respectively\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]Alice, Bob, and Carol\[dq] | index(\[dq], \[dq]) \-\-> 5\f[R] .IP \[bu] 2 \f[CB][0, 1, 2, 3, 1, 2, 3] | rindex([1, 2]) \-\-> 4\f[R] .IP \[bu] 2 \f[CB]\[dq]Hello world!\[dq] | index(\[dq], \[dq]) \-\-> null\f[R] .IP \[bu] 2 \f[CB][0, 1, 2] | rindex(3) \-\-> null\f[R] .RE .SS \f[CB]has($k)\f[R], \f[CB]in($x)\f[R] .PP The filter \f[CB]has($k)\f[R] yields \f[CB]true\f[R] if \f[CB]\&.[$k]\f[R] points to data in the input, else \f[CB]false\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | has( 0 , 3 ) \-\-> true false\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} | has(\[dq]a\[dq], \[dq]c\[dq]) \-\-> true false\f[R] .RE .PP The filter \f[CB]in($x)\f[R] is a flipped version of \f[CB]has\f[R], just like \f[CB]inside\f[R] is a flipped version of \f[CB]contains\f[R]\&. For example, \f[CB]\[dq]a\[dq] | in({a: 1, b: 2}) \-\-> true\f[R]\&. .PP \f[I]سازگاری\f[R] .RS Whenever \f[CB]has($k)\f[R] in \f[CB]jq\f[R] returns \f[CB]true\f[R], jaq also returns \f[CB]true\f[R]\&. However, when \f[CB]has($k)\f[R] yields \f[CB]true\f[R] in jaq, it may also yield \f[CB]false\f[R] or an error in \f[CB]jq\f[R]: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | has(\-1, \-2, \-3) \-\-> true true true\f[R] (\f[CB]false false false\f[R] in \f[CB]jq\f[R]) .IP \[bu] 2 \f[CB][1, 2, 3] | has({start: 1}) \-\-> true\f[R] (error in \f[CB]jq\f[R]) .RE .PP This difference arises because in \f[CB]jq\f[R], \f[CB]has($k)\f[R] has a much weaker relationship with \f[CB]\&.[$k]\f[R] than in jaq\&. The following properties hold in both \f[CB]jq\f[R] and jaq: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | \&.[\-1, \-2, \-3] \-\-> 3 2 1\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | \&.[{start: 1}] \-\-> [2, 3]\f[R] .RE .RE .SS "به‌روزرسانی‌ها (UPDATES)" .SS \f[CB]map(f)\f[R], \f[CB]map_values(f)\f[R] .PP The filter \f[CB]map(f)\f[R] obtains all values of the input (via \f[CB]\&.[]\f[R]), applies \f[CB]f\f[R] to the values, and collects all results into an array\&. For example: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | map(\&., \&.*2) \-\-> [1, 2, 2, 4, 3, 6]\f[R]\&. .IP \[bu] 2 \f[CB]{a: 1, b: 2} | map(\&., \&.*2) \-\-> [1, 2, 2, 4]\f[R]\&. .IP \[bu] 2 \f[CB][1, 2, 3, 4] | map(select(\&. % 2 == 0)) \-\-> [2, 4]\f[R]\&. .RE .PP The filter \f[CB]map_values(f)\f[R] has the same effect as \f[CB]map(f)\f[R] when the input is an array, but when the input is an object, \f[CB]map_values(f)\f[R] also outputs an object\&. For example: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3, 4] | map_values(\&.*2) \-\-> [2, 4, 6, 8]\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} | map_values(\&.*2) \-\-> {\[dq]a\[dq]: 2, \[dq]b\[dq]: 4}\f[R] .RE .SS \f[CB]walk(f)\f[R] .PP The filter \f[CB]walk(f)\f[R] recursively updates its input with \f[CB]f\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB][[1, 2], [3]] | walk(numbers += 1) \-\-> [[2, 3], [4]]\f[R] .RE .SS \f[CB]del(f)\f[R] .PP The filter \f[CB]del(f)\f[R] deletes values at the locations given by \f[CB]f\f[R]\&. It is equivalent to \f[CB]f |= empty\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3, 4] | del(\&.[] | select(\&. % 2 == 0)) \-\-> [1, 3]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | del(\&.[1]) \-\-> [1, 3]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | del(\&.[1:]) \-\-> [1]\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} | del(\&.a) \-\-> {\[dq]b\[dq]: 2}\f[R] .RE .SS "مسیرها (PATHS)" .SS \f[CB]path(f)\f[R] .PP The filter \f[CB]path(f)\f[R] records for each output of \f[CB]f\f[R] its position in the input, and yields that position as a \f[B]path\f[R]\&. A path is an array that may contain indices or “slice objects”\&. The latter must contain a \f[CB]\[dq]start\[dq]\f[R] and/or an \f[CB]\[dq]end\[dq]\f[R] key with an integer value\&. For example: .RS 2 .IP \[bu] 2 \f[CB][{a: 1}, {a: 2}] | path(\&.[]\&.a) \-\-> [0, \[dq]a\[dq]] [1, \[dq]a\[dq]]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | path(\&.[1:][:\-1]) \-\-> [{\[dq]start\[dq]: 1}, {\[dq]end\[dq]: \-1}]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | path(\&.[1: \-1]) \-\-> [{\[dq]start\[dq]: 1, \[dq]end\[dq]: \-1}]\f[R] .RE .PP If \f[CB]f\f[R] returns values that do not point to the input, then \f[CB]path(f)\f[R] yields an error\&. .RS 2 .IP \[bu] 2 \f[CB]try path(0 ) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .IP \[bu] 2 \f[CB]try path(\&. as $x | $x) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .RE .SS \f[CB]paths\f[R], \f[CB]paths(p)\f[R] .PP The filter \f[CB]paths\f[R] yields the paths to all ancestor values of the input\&. It is equivalent to \f[CB]skip(1; path(\&.\&.))\f[R]\&. .PP The filter \f[CB]paths(p)\f[R] yields the paths to all ancestor values of the input for which \f[CB]p\f[R] yields true\&. .PP Examples: .RS 2 .IP \[bu] 2 \f[CB][1, {a: 2}] | paths \-\-> [0] [1] [1, \[dq]a\[dq]]\f[R] .IP \[bu] 2 \f[CB][1, {a: 2}] | paths(isnumber) \-\-> [0] [1, \[dq]a\[dq]]\f[R] .IP \[bu] 2 \f[CB][1, {a: 2}] | paths(isobject) \-\-> [1] \f[R] .RE .SS \f[CB]getpath($path)\f[R] .PP The filter \f[CB]getpath($path)\f[R] is the inverse filter for \f[CB]path(f)\f[R]\&. If \f[CB]path(f)\f[R] yields no error, then \f[CB]getpath(path(f))\f[R] yields the same outputs as \f[CB]f\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB][{a: 1}, {a: 2}] | getpath([0, \[dq]a\[dq]], [1, \[dq]a\[dq]]) \-\-> 1 2\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | getpath([{\[dq]start\[dq]: 1}, {\[dq]end\[dq]: \-1}]) \-\-> [2]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | getpath([{\[dq]start\[dq]: 1, \[dq]end\[dq]: \-1}]) \-\-> [2]\f[R] .RE .SS \f[CB]setpath($path; $v)\f[R] .PP فیلتر \f[CB]setpath($path; $v)\f[R] مقدار موجود در مسیر \f[CB]$path\f[R] را روی \f[CB]$v\f[R] تنظیم می‌کند\&. It is equivalent to \f[CB]getpath($path) = $v\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB][[1, 2], [3, 4]] | setpath([1, 0]; 5) \-\-> [[1, 2], [5, 4]]\f[R] .RE .SS \f[CB]delpaths($paths)\f[R] .PP The filter \f[CB]delpaths($paths)\f[R] takes an array of paths and deletes all corresponding values in the order given by the array\&. For example: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | delpaths([[0]]) \-\-> [2, 3]\f[R] .IP \[bu] 2 \f[CB][{a: 1, b: 2}, 3] | delpaths([[0, \[dq]b\[dq]], [1]]) \-\-> [{\[dq]a\[dq]: 1}]\f[R] .RE .PP \f[I]سازگاری\f[R] .RS In \f[CB]jq\f[R], the \f[CB]$paths\f[R] are interpreted relative to the \f[I]original\f[R] input value, whereas in jaq, they are interpreted relative to the \f[I]current\f[R] value\&. For example, \f[CB][1, 2, 3] | delpaths([[0], [0]]) \-\-> [3]\f[R] in jaq, because it first deletes the \f[CB]0\f[R]\-th element \f[CB]1\f[R] (yielding \f[CB][2, 3]\f[R]), then it deletes the \f[CB]0\f[R]\-th element \f[CB]2\f[R] (yielding \f[CB][3]\f[R])\&. Here, \f[CB]jq\f[R] yields \f[CB][2, 3]\f[R], because the \f[CB]0\f[R]\-th element always refers to the \f[CB]0\f[R]\-th element of the original input, which is \f[CB]1\f[R]\&. .PP To use \f[CB]delpaths\f[R] in an interoperable fashion, use \f[CB]$paths\f[R] such that: .RS 2 .IP \[bu] 2 Paths to descendants come before paths to their ancestors\&. .IP \[bu] 2 Paths to array elements to the right come before paths to elements to the left\&. .RE .PP For example, \f[CB]\&.\&.\f[R] returns \f[I]ancestors\f[R] before descendants and array elements to the \f[I]left\f[R] before elements to the right\&. To use the output of \f[CB]\&.\&.\f[R] in \f[CB]delpaths\f[R], it suffices to reverse the order of its outputs: .RS 2 .IP \[bu] 2 \f[CB][\[dq]a\[dq], 0, \[dq]b\[dq], 1] | delpaths([path(\&.\&. | strings)] | reverse) \-\-> [0, 1 ]\f[R] (right) .IP \[bu] 2 \f[CB][\[dq]a\[dq], 0, \[dq]b\[dq], 1] | delpaths([path(\&.\&. | strings)] ) \-\-> [0, \[dq]b\[dq]]\f[R] (wrong) .RE .RE .SS \f[CB]pick(f)\f[R] .PP The filter \f[CB]pick(f)\f[R] constructs an object that contains only those parts of the input that \f[CB]f\f[R] returns\&. For example: .RS 2 .IP \[bu] 2 \f[CB]{a: {b: 1, c: 2}, d: 3} | pick(\&. ) \-\-> {\[dq]a\[dq]: {\[dq]b\[dq]: 1, \[dq]c\[dq]: 2}, \[dq]d\[dq]: 3}\f[R] .IP \[bu] 2 \f[CB]{a: {b: 1, c: 2}, d: 3} | pick(\&.a\&.c ) \-\-> {\[dq]a\[dq]: { \[dq]c\[dq]: 2} }\f[R] .IP \[bu] 2 \f[CB]{a: {b: 1, c: 2}, d: 3} | pick(\&.a\&.c, \&.d) \-\-> {\[dq]a\[dq]: { \[dq]c\[dq]: 2}, \[dq]d\[dq]: 3}\f[R] .RE .PP \f[I]سازگاری\f[R] .RS In \f[CB]jq\f[R], \f[CB]pick(f)\f[R] also supports paths to arrays; for example: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | pick(\&.[0 ])\f[R] yields \f[CB][1]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | pick(\&.[1 ])\f[R] yields \f[CB][null, 2]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | pick(\&.[1:])\f[R] yields \f[CB][2, 3]\f[R] .RE .PP While implementing this functionality in jaq, I found many corner cases that would have made the proper documentation of this filter very complex\&. I also found a few surprising behaviours in \f[CB]jq\f[R], e\&.g\&. that \f[CB][1, 2, 3] | pick(\&.[\-1])\f[R] yields an error\&. In the end, I decided to support only the simpler and well\-understandable subset of paths to objects\&. .RE .SS "بولی‌ها (BOOLEANS)" .SS \f[CB]true\f[R], \f[CB]false\f[R] .PP The filters \f[CB]true\f[R] and \f[CB]false\f[R] yield the values \f[CB]true\f[R] and \f[CB]false\f[R], respectively: .RS 2 .IP \[bu] 2 \f[CB]true \-\-> true\f[R] .IP \[bu] 2 \f[CB]false \-\-> false\f[R] .RE .SS \f[CB]not\f[R] .PP The filter \f[CB]not\f[R] converts its input to its boolean value and returns its negation\&. For example: .RS 2 .IP \[bu] 2 \f[CB]true | not \-\-> false\f[R] .IP \[bu] 2 \f[CB]false | not \-\-> true\f[R] .IP \[bu] 2 \f[CB]\[dq]foo\[dq] | not \-\-> false\f[R] .RE .SS \f[CB]toboolean\f[R] .PP The filter \f[CB]toboolean\f[R] is for booleans what \f[CB]tonumber\f[R] is for numbers\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\ true | toboolean \-\-> true\f[R] .IP \[bu] 2 \f[CB]\ \[dq]true\[dq] | toboolean \-\-> true\f[R] .IP \[bu] 2 \f[CB]\[dq][true]\[dq] | try toboolean catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .RE .SS "اعداد (NUMBERS)" .SS \f[CB]tonumber\f[R] .PP The filter \f[CB]tonumber\f[R] takes as input either a number or a string\&. If the input is a number, it is returned unchanged; if the input is a string, it is parsed to a number, failing if this does not succeed\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\ 42 | tonumber \-\-> 42\f[R] .IP \[bu] 2 \f[CB]\ \[dq]42\[dq] | tonumber \-\-> 42\f[R] .IP \[bu] 2 \f[CB]\[dq][42]\[dq] | try tonumber catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .RE .SS \f[CB]infinite\f[R], \f[CB]nan\f[R] .PP The filters \f[CB]infinite\f[R] and \f[CB]nan\f[R] yield the floating\-point numbers \f[CB]Infinity\f[R] and \f[CB]NaN\f[R]: .RS 2 .IP \[bu] 2 \f[CB]infinite \-\-> Infinity\f[R] .IP \[bu] 2 \f[CB]nan | isnan \-\-> true\f[R] (we cannot test for equality with \f[CB]NaN\f[R] here, because \f[CB]nan == nan \-\-> false\f[R]) .RE .SS \f[CB]abs\f[R] .PP The filter \f[CB]abs\f[R] yields the negation of the input if the input is smaller than \f[CB]0\f[R], else it yields the input\&. Note that due to this definition, strings, arrays, and objects are also returned unchanged, because they are larger than \f[CB]0\f[R]; see ordering\&. .PP Examples: .RS 2 .IP \[bu] 2 \f[CB]\-2\&.0, \-1, 0, 1, 2\&.0 | abs \-\-> 2\&.0 1 0 1 2\&.0\f[R] .IP \[bu] 2 \f[CB]\[dq]foo\[dq], [], {} | abs \-\-> \[dq]foo\[dq] [] {}\f[R] .RE .SS \f[CB]floor\f[R], \f[CB]round\f[R], \f[CB]ceil\f[R] .PP The filters \f[CB]floor\f[R], \f[CB]round\f[R] and \f[CB]ceil\f[R] round a number to its closest smaller integer, to its closest integer, and to its closest larger integer, respectively\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\ 0\&.5 | floor, round, ceil \-\-> 0 1 1\f[R] .IP \[bu] 2 \f[CB]\ 0\&.4 | floor, round, ceil \-\-> 0 0 1\f[R] .IP \[bu] 2 \f[CB]\ 0\&.0 | floor, round, ceil \-\-> 0 0 0\f[R] .IP \[bu] 2 \f[CB]\-0\&.4 | floor, round, ceil \-\-> \-1 0 0\f[R] .IP \[bu] 2 \f[CB]\-0\&.5 | floor, round, ceil \-\-> \-1 \-1 0\f[R] .IP \[bu] 2 \f[CB]0, 1 | round \-\-> 0 1\f[R] .IP \[bu] 2 \f[CB]nan | round | isnan \-\-> true\f[R] .IP \[bu] 2 \f[CB]infinite | round \-\-> Infinity\f[R] .RE .SS "ریاضیات (Math)" .PP jaq implements many mathematical functions via \c .UR https://docs.rs/libm \f[CB]libm\f[R] .UE \c \&. If not specified otherwise, these filters take and return floating\-point numbers\&. .PP Zero\-argument filters: .RS 2 .IP \[bu] 2 \f[CB]acos\f[R] .IP \[bu] 2 \f[CB]acosh\f[R] .IP \[bu] 2 \f[CB]asin\f[R] .IP \[bu] 2 \f[CB]asinh\f[R] .IP \[bu] 2 \f[CB]atan\f[R] .IP \[bu] 2 \f[CB]atanh\f[R] .IP \[bu] 2 \f[CB]cbrt\f[R] .IP \[bu] 2 \f[CB]cos\f[R] .IP \[bu] 2 \f[CB]cosh\f[R] .IP \[bu] 2 \f[CB]erf\f[R] .IP \[bu] 2 \f[CB]erfc\f[R] .IP \[bu] 2 \f[CB]exp\f[R] .IP \[bu] 2 \f[CB]exp10\f[R] .IP \[bu] 2 \f[CB]exp2\f[R] .IP \[bu] 2 \f[CB]expm1\f[R] .IP \[bu] 2 \f[CB]fabs\f[R] .IP \[bu] 2 \f[CB]frexp\f[R], which returns pairs of (float, integer)\&. .IP \[bu] 2 \f[CB]gamma\f[R] .IP \[bu] 2 \f[CB]ilogb\f[R], which returns integers\&. .IP \[bu] 2 \f[CB]j0\f[R] .IP \[bu] 2 \f[CB]j1\f[R] .IP \[bu] 2 \f[CB]lgamma\f[R] .IP \[bu] 2 \f[CB]log\f[R] .IP \[bu] 2 \f[CB]log10\f[R] .IP \[bu] 2 \f[CB]log1p\f[R] .IP \[bu] 2 \f[CB]log2\f[R] .IP \[bu] 2 \f[CB]logb\f[R] .IP \[bu] 2 \f[CB]modf\f[R], which returns pairs of (float, float)\&. .IP \[bu] 2 \f[CB]nearbyint\f[R] .IP \[bu] 2 \f[CB]pow10\f[R] .IP \[bu] 2 \f[CB]rint\f[R] .IP \[bu] 2 \f[CB]significand\f[R] .IP \[bu] 2 \f[CB]sin\f[R] .IP \[bu] 2 \f[CB]sinh\f[R] .IP \[bu] 2 \f[CB]sqrt\f[R] .IP \[bu] 2 \f[CB]tan\f[R] .IP \[bu] 2 \f[CB]tanh\f[R] .IP \[bu] 2 \f[CB]tgamma\f[R] .IP \[bu] 2 \f[CB]trunc\f[R] .IP \[bu] 2 \f[CB]y0\f[R] .IP \[bu] 2 \f[CB]y1\f[R] .RE .PP Two\-argument filters that ignore \f[CB]\&.\f[R]: .RS 2 .IP \[bu] 2 \f[CB]atan2\f[R] .IP \[bu] 2 \f[CB]copysign\f[R] .IP \[bu] 2 \f[CB]drem\f[R] .IP \[bu] 2 \f[CB]fdim\f[R] .IP \[bu] 2 \f[CB]fmax\f[R] .IP \[bu] 2 \f[CB]fmin\f[R] .IP \[bu] 2 \f[CB]fmod\f[R] .IP \[bu] 2 \f[CB]hypot\f[R] .IP \[bu] 2 \f[CB]jn\f[R], which takes an integer as first argument\&. .IP \[bu] 2 \f[CB]ldexp\f[R], which takes an integer as second argument\&. .IP \[bu] 2 \f[CB]nextafter\f[R] .IP \[bu] 2 \f[CB]nexttoward\f[R] .IP \[bu] 2 \f[CB]pow\f[R] .IP \[bu] 2 \f[CB]remainder\f[R] .IP \[bu] 2 \f[CB]scalb\f[R] .IP \[bu] 2 \f[CB]scalbln\f[R], which takes as integer as second argument\&. .IP \[bu] 2 \f[CB]yn\f[R], which takes an integer as first argument\&. .RE .PP Three\-argument filters that ignore \f[CB]\&.\f[R]: .RS 2 .IP \[bu] 2 \f[CB]fma\f[R] .RE .PP Examples: .RS 2 .IP \[bu] 2 \f[CB](3\&.141592 | sin) < (\-5 | pow10) \-\-> true\f[R] establishes that \f[CB]sin(pi)\f[R] is smaller than \f[CB]10^\-5\f[R]\&. .IP \[bu] 2 \f[CB]fmax(2; 3) \-\-> 3\&.0\f[R] .IP \[bu] 2 \f[CB]fma(2; 3; 4) \-\-> 10\&.0\f[R] .RE .SS "آرایه‌ها (ARRAYS)" .SS \f[CB]sort\f[R], \f[CB]sort_by(f)\f[R] .PP فیلتر \f[CB]sort\f[R] یک آرایه را دریافت کرده و عناصر آن را مرتب می‌کند\&. برای نمونه: .IP .EX [true, 1, \[dq]abc\[dq], [1], {\[dq]a\[dq]: 1}, null, false, 0, \[dq]ABC\[dq], [], {}] | sort \-\-> [null, false, true, 0, 1, \[dq]ABC\[dq], \[dq]abc\[dq], [], [1], {}, {\[dq]a\[dq]: 1}] .EE .PP فیلتر \f[CB]sort_by(f)\f[R] فیلتر \f[CB]f\f[R] را برای هر مقدار در آرایه ورودی ارزیابی کرده، و مقادیر را بر اساس خروجی \f[CB]f\f[R] مرتب می‌سازد\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][0, 1, 2, 3] | sort_by(\&. % 2) \-\-> [0, 2, 1, 3]\f[R] .IP \[bu] 2 \f[CB][{a: 1, b: 2}, {a: 0, b: 3}] | sort_by(\&. ) \-\-> [{\[dq]a\[dq]: 0, \[dq]b\[dq]: 3}, {\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}]\f[R] .IP \[bu] 2 \f[CB][{a: 1, b: 2}, {a: 0, b: 3}] | sort_by(\&.a) \-\-> [{\[dq]a\[dq]: 0, \[dq]b\[dq]: 3}, {\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}]\f[R] .IP \[bu] 2 \f[CB][{a: 1, b: 2}, {a: 0, b: 3}] | sort_by(\&.b) \-\-> [{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}, {\[dq]a\[dq]: 0, \[dq]b\[dq]: 3}]\f[R] .RE .SS \f[CB]group_by(f)\f[R] .PP فیلتر \f[CB]group_by(f)\f[R] آرایه ورودی را بر اساس \f[CB]f\f[R] مرتب کرده، سپس تمامی مقادیری را که \f[CB]f\f[R] برای آن‌ها خروجی‌های یکسانی تولید کرده در یک آرایه گروه‌بندی می‌کند\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][\[dq]foo\[dq], \[dq]\[dq], \[dq]bar\[dq], \[dq]quux\[dq], \[dq]baz\[dq]] | group_by(length) \-\-> [[\[dq]\[dq]], [\[dq]foo\[dq], \[dq]bar\[dq], \[dq]baz\[dq]], [\[dq]quux\[dq]]]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3, 4] | group_by(\&. % 2) \-\-> [[2, 4], [1, 3]]\f[R] .RE .SS \f[CB]unique\f[R], \f[CB]unique_by(f)\f[R] .PP فیلتر \f[CB]unique_by(f)\f[R] آرایه ورودی را بر اساس \f[CB]f\f[R] مرتب می‌کند\&. اگر \f[CB]f\f[R] برای چندین مقدار در آرایه خروجی‌های یکسانی تولید کند، تنها اولین مقدار نگه داشته می‌شود\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][\[dq]foo\[dq], \[dq]\[dq], \[dq]bar\[dq], \[dq]quux\[dq], \[dq]baz\[dq]] | unique_by(length) \-\-> [\[dq]\[dq], \[dq]foo\[dq], \[dq]quux\[dq]]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3, 4] | unique_by(\&. % 2) \-\-> [2, 1]\f[R] .RE .PP فیلتر \f[CB]unique\f[R] معادل با \f[CB]unique_by(\&.)\f[R] است\&. این فیلتر آرایه ورودی را مرتب کرده و تمام عناصر تکراری را حذف می‌کند؛ مثلاً: \f[CB][3, 2, 1, 3, 4] | unique \-\-> [1, 2, 3, 4]\f[R]\&. .SS \f[CB]min\f[R], \f[CB]max\f[R], \f[CB]min_by(f)\f[R], \f[CB]max_by(f)\f[R] .PP فیلترهای \f[CB]min\f[R] و \f[CB]max\f[R] به ترتیب کوچک‌ترین و بزرگ‌ترین عنصر یک آرایه را تولید می‌کنند\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | min \-\-> 1\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | max \-\-> 3\f[R] .RE .PP The filters \f[CB]min_by(f)\f[R] and \f[CB]max_by(f)\f[R] evaluate the filter \f[CB]f\f[R] for each value in the input array, and yield the value for which \f[CB]f\f[R] produces the smallest or largest output, respectively\&. For example: .RS 2 .IP \[bu] 2 \f[CB][\[dq]abc\[dq], [1, 2], {\[dq]a\[dq]: 1}] | min_by(length) \-\-> {\[dq]a\[dq]: 1}\f[R] .IP \[bu] 2 \f[CB][\[dq]abc\[dq], [1, 2], {\[dq]a\[dq]: 1}] | max_by(length) \-\-> \[dq]abc\[dq]\f[R] .RE .PP You can yield multiple values in \f[CB]f\f[R] to break ties such as: .RS 2 .IP \[bu] 2 \f[CB][\[dq]abc\[dq], [1, 2], {\[dq]a\[dq]: 1, \[dq]b\[dq]: 3}] | min_by(length, add?) \-\-> [1, 2]\f[R] .RE .SS \f[CB]reverse\f[R] .PP The filter \f[CB]reverse\f[R] takes an array and reverses it\&. For example, \f[CB][1, 2, 3] | reverse \-\-> [3, 2, 1]\f[R]\&. .SS \f[CB]transpose\f[R] .PP The filter \f[CB]transpose\f[R] takes an array of arrays and yields its transposition\&. .PP Examples: .RS 2 .IP \[bu] 2 \f[CB][[1 , 2, 3], [4, 5, 6]] | transpose \-\-> [[1, 4], [2, 5], [3, 6]]\f[R] .IP \[bu] 2 \f[CB][[1], [2, 3], [4, 5, 6]] | transpose \-\-> [[1, 2, 4], [null, 3, 5], [null, null, 6]]\f[R] .RE .SS \f[CB]flatten\f[R], \f[CB]flatten($depth)\f[R] .PP The filter \f[CB]flatten\f[R] flattens input arrays, and the filter \f[CB]flatten($depth)\f[R] flattens input arrays up to a certain depth\&. For example: .RS 2 .IP \[bu] 2 \f[CB][1, [2, [3]], {a: [1, [2]]}] | flatten \-\-> [1, 2, 3 , {\[dq]a\[dq]: [1, [2]]}]\f[R] .IP \[bu] 2 \f[CB][1, [2, [3]], {a: [1, [2]]}] | flatten(0) \-\-> [1, [2, [3]], {\[dq]a\[dq]: [1, [2]]}]\f[R] .IP \[bu] 2 \f[CB][1, [2, [3]], {a: [1, [2]]}] | flatten(1) \-\-> [1, 2, [3] , {\[dq]a\[dq]: [1, [2]]}]\f[R] .IP \[bu] 2 \f[CB][1, [2, [3]], {a: [1, [2]]}] | flatten(2) \-\-> [1, 2, 3 , {\[dq]a\[dq]: [1, [2]]}]\f[R] .IP \[bu] 2 \f[CB]null, true, 0, \[dq]Hi\[dq] | flatten \-\-> [null] [true] [0] [\[dq]Hi\[dq]]\f[R] .RE .PP Note that \f[CB]flatten\f[R] does not impact arrays that are descendants of an object\&. .SS \f[CB]bsearch($x)\f[R] .PP The filter \f[CB]bsearch($x)\f[R] takes a sorted array and performs a binary search for \f[CB]$x\f[R] in the array\&. If the array contains \f[CB]$x\f[R], then the filter yields a positive \f[CB]$i\f[R] such that \f[CB]\&.[$i] == $x\f[R]; otherwise, the filter yields a negative \f[CB]$i\f[R] such that inserting \f[CB]$x\f[R] at the index \f[CB]\-$i\-1\f[R] in the array would preserve its the ordering\&. .PP Examples: .RS 2 .IP \[bu] 2 \f[CB][0, 4, 8] | bsearch(8, 4, 0) \-\-> 2 1 0\f[R] .IP \[bu] 2 \f[CB][0, 4, 8] | bsearch(\-2, 2, 6, 10) \-\-> \-1 \-2 \-3 \-4\f[R] .RE .PP If the input array is not sorted, then the output of this filter is meaningless\&. .SS \f[CB]combinations\f[R], \f[CB]combinations($n)\f[R] .PP The filter \f[CB]combinations\f[R] takes as input an array of arrays, such as \f[CB][a1, \&.\&.\&., an]\f[R]\&. It yields all combinations of the elements of the arrays \f[CB]a1\f[R] to \f[CB]an\f[R]: .IP .EX [[1, 2], [3, 4]] | combinations \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE .PP When the input array is empty, \f[CB]combinations\f[R] yields an empty array; \f[CB][] | combinations \-\-> []\f[R]\&. .PP The filter \f[CB]combinations($n)\f[R] takes a single array \f[CB]a1\f[R] as input\&. Its output is equivalent to \f[CB][a1, \&.\&.\&., a1] | combinations\f[R], where \f[CB]a1\f[R] is repeated \f[CB]$n\f[R] times\&. .IP .EX [1, 2] | combinations(2) \-\-> [1, 1] [1, 2] [2, 1] [2, 2] .EE .SS "رشته‌های متنی (TEXT STRINGS)" .PP Unless stated otherwise, all filters in this section take a text string as input, and fail if the input is of any other type\&. .SS \f[CB]tostring\f[R] .PP فیلتر \f[CB]tostring\f[R] ورودی خود را به یک رشته تبدیل می‌کند\&. Its output depends on the type of its input: .RS 2 .IP \[bu] 2 Text strings are returned unchanged, i\&.e\&. \f[CB]\[dq]Hi\[dq] | tostring \-\-> \[dq]Hi\[dq]\f[R]\&. .IP \[bu] 2 Byte strings are interpreted as text string, i\&.e\&. \f[CB]\[dq]Hi\[dq] | tobytes | tostring \-\-> \[dq]Hi\[dq]\f[R]\&. This takes constant time\&. .IP \[bu] 2 Any other value is formatted compactly as if output by \f[CB]jaq \-c\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]null | tostring \-\-> \[dq]null\[dq]\f[R], .IP \[bu] 2 \f[CB][0, 1] | tostring \-\-> \[dq][0,1]\[dq]\f[R], .IP \[bu] 2 \f[CB]{a: 1} | tostring \-\-> \[dq]{\[rs]\[dq]a\[rs]\[dq]:1}\[dq]\f[R]\&. .RE .RE .SS \f[CB]utf8bytelength\f[R] .PP The filter \f[CB]utf8bytelength\f[R] yields the number of bytes of the input string\&. It is equivalent to \f[CB]tobytes | length\f[R], but different from \f[CB]length\f[R], which counts the number of \f[B]characters\f[R]\&. .PP For example, \f[CB]\[dq]ゼノギアス\[dq] | length, utf8bytelength, (tobytes | length) \-\-> 5 15 15\f[R]\&. .SS \f[CB]startswith($s)\f[R], \f[CB]endswith($s)\f[R] .PP The filter \f[CB]startswith($s)\f[R] yields \f[CB]true\f[R] if the input string starts with the string \f[CB]$s\f[R], else \f[CB]false\f[R]\&. Similar for \f[CB]endswith($s)\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]ゼノギアス\[dq] | startswith(\[dq]ゼノ\[dq]) \-\-> true\f[R] .IP \[bu] 2 \f[CB]\[dq]ゼノギアス\[dq] | endswith(\[dq]ギアス\[dq]) \-\-> true\f[R] .RE .SS \f[CB]trim\f[R], \f[CB]ltrim\f[R], \f[CB]rtrim\f[R] .PP The filters \f[CB]ltrim\f[R] and \f[CB]rtrim\f[R] remove from the input string all leading and trailing whitespace, respectively\&. Here, whitespace corresponds to the \f[CB]White_Space\f[R] Unicode property\&. The filter \f[CB]trim\f[R] is equivalent to \f[CB]ltrim | rtrim\f[R]\&. .PP For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq] \[rs]t\[rs]n Bonjour !   \[rs]r  \[dq] | ltrim \-\-> \[dq]Bonjour !   \[rs]r  \[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq] \[rs]t\[rs]n Bonjour !   \[rs]r  \[dq] | rtrim \-\-> \[dq] \[rs]t\[rs]n Bonjour !\[dq]\f[R] .RE .PP Note that there are a few quite unusual whitespace characters in this string\&. .SS \f[CB]ltrimstr($s)\f[R], \f[CB]rtrimstr($s)\f[R] .PP The filters \f[CB]ltrimstr($s)\f[R] and \f[CB]rtrimstr($s)\f[R] remove a single occurrence of \f[CB]$s\f[R] from the start or the end of the string, respectively\&. If there is no such occurrence, the original string is returned\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]foofoobar\[dq] | ltrimstr(\[dq]foo\[dq]) \-\-> \[dq]foobar\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]foobarbar\[dq] | rtrimstr(\[dq]bar\[dq]) \-\-> \[dq]foobar\[dq]\f[R] .RE .SS \f[CB]explode\f[R], \f[CB]implode\f[R] .PP The filter \f[CB]explode\f[R] yields an array containing a positive number for each valid Unicode code point of the input string and a negative number for each byte of each invalid Unicode code unit\&. For example: .IP .EX \[dq]Dear ☀️\[dq] + (255 | tobytes | tostring) | explode \-\-> [68,101,97,114,32,9728,65039,\-255] .EE .PP Here, we can see that \f[CB]\[dq]☀️\[dq]\f[R] has turned into two code points, namely \f[CB]9728\f[R] and \f[CB]65039\f[R], whereas the invalid \f[CB]FF\f[R] byte (= 255) has become \f[CB]\-255\f[R]\&. .PP The inverse filter of \f[CB]explode\f[R] is \f[CB]implode\f[R]: .IP .EX [68,101,97,114,32,9728,65039, \-255] | implode[:\-1] \-\-> \[dq]Dear ☀️\[dq] .EE .PP (I omitted the \f[CB]FF\f[R] byte at the end, because it is hard to save in a text editor\&.) .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] does not permit invalid code units in text strings, so it returns and accepts only natural numbers in \f[CB]explode\f[R] and \f[CB]implode\f[R]\&. .RE .SS \f[CB]split($s)\f[R] .PP This filter yields \f[CB]\&. / $s\f[R] if its input \f[CB]\&.\f[R] and \f[CB]$s\f[R] are both strings, else it fails\&. See the section on division for details\&. .PP Note that there is also \f[CB]split($re; $flags)\f[R] that splits by a regex\&. .SS \f[CB]join($s)\f[R] .PP The filter \f[CB]join($s)\f[R] takes as input an array \f[CB][x1, \&.\&.\&., xn]\f[R] and yields \f[CB]\[dq]\[dq]\f[R] if the array is empty, otherwise \f[CB]\[dq]\[rs](x1)\[dq] + $s + \&.\&.\&. + $s + \[dq]\[rs](xn)\[dq]\f[R]\&. That is, it concatenates the string representations of the array values interspersed with \f[CB]$s\f[R]\&. .PP For example, to memorise the hierarchy of values in jq: \f[CB][\[dq]null\[dq], \[dq]boolean\[dq], \[dq]number\[dq], \[dq]string\[dq], \[dq]array\[dq], \[dq]object\[dq]] | join(\[dq] < \[dq]) \-\-> \[dq]null < boolean < number < string < array < object\[dq]\f[R]\&. .PP \f[I]سازگاری\f[R] .RS Unlike jq, jaq does not map \f[CB]null\f[R] values in the array to \f[CB]\[dq]\[dq]\f[R], nor does it reject array or object values in the array\&. .RE .SS \f[CB]ascii_downcase\f[R], \f[CB]ascii_upcase\f[R] .PP The filters \f[CB]ascii_downcase\f[R] and \f[CB]ascii_upcase\f[R] convert all ASCII letters in the input string to their lower/upper case variants, respectively\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]Der λΠ\-Kalkül\[dq] | ascii_downcase \-\-> \[dq]der λΠ\-kalkül\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]Der λΠ\-Kalkül\[dq] | ascii_upcase \-\-> \[dq]DER λΠ\-KALKüL\[dq]\f[R] .RE .SS "قالب‌بندی رشته‌های متنی (TEXT STRING FORMATTING)" .PP The filters in this section can be prefixed to strings to influence string interpolation\&. However, these filters can also be used outside of string interpolation\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]1 + 2 * 3\[dq] | @uri \[dq]https://duckduckgo\&.com/?q=\[rs](\&.)\[dq] \-\-> \[dq]https://duckduckgo\&.com/?q=1%20%2B%202%20%2A%203\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]1 + 2 * 3\[dq] | @uri \-\-> \[dq]1%20%2B%202%20%2A%203\[dq]\f[R] .RE .PP If not indicated otherwise, all filters in this section convert their input to a string with \f[CB]tostring\f[R] and yield a single string output\&. As result, byte strings are treated like equivalent text strings; e\&.g\&. \f[CB]\[dq]Hello world!\[dq] | (tobytes | @base64) == @base64 \-\-> true\f[R]\&. .PP \f[I]سازگاری\f[R] .RS Unlike in \f[CB]jq\f[R], you can define you own filters that start with \f[CB]@\f[R]; for example, \f[CB]def @xml: @html;\f[R] .RE .SS \f[CB]@text\f[R] .PP The filter \f[CB]@text\f[R] is equivalent to \f[CB]tostring\f[R]\&. .SS \f[CB]@json\f[R] .PP The filter \f[CB]@json\f[R] is equivalent to \f[CB]tojson\f[R]\&. .SS \f[CB]@csv\f[R], \f[CB]@tsv\f[R] .PP The filters \f[CB]@csv\f[R] and \f[CB]@tsv\f[R] are equivalent to \f[CB]tocsv\f[R] and \f[CB]totsv\f[R], respectively\&. .SS \f[CB]@html\f[R], \f[CB]@htmld\f[R] .PP The filter \f[CB]@html\f[R] escapes a string so that it can be embedded in an HTML document\&. It replaces the following characters by HTML equivalents: .RS 2 .IP \[bu] 2 \f[CB]\[dq]<\[dq] | @html \-\-> \[dq]<\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]>\[dq] | @html \-\-> \[dq]>\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]&\[dq] | @html \-\-> \[dq]&\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]\[aq]\[dq] | @html \-\-> \[dq]'\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]\[rs]\[dq]\[dq] | @html \-\-> \[dq]"\[dq]\f[R] .RE .PP The filter \f[CB]@htmld\f[R] reverses the effect of \f[CB]@html\f[R]\&. For example: .IP .EX \[dq]\[rs]\[dq]1 < 2 & 2 > 1\[rs]\[dq], that\[aq]s what he said\&.\[dq] | @html | \&., @htmld \-\-> \[dq]"1 < 2 & 2 > 1", that's what he said\&.\[dq] \[dq]\[rs]\[dq]1 < 2 & 2 > 1\[rs]\[dq], that\[aq]s what he said\&.\[dq] .EE .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] does not support \f[CB]@htmld\f[R]\&. .RE .SS \f[CB]@base64\f[R], \f[CB]@base64d\f[R] .PP The filter \f[CB]@base64\f[R] \c .UR https://en.wikipedia.org/wiki/Base64 Base64 .UE \c \-encodes its input\&. The filter \f[CB]@base64d\f[R] reverses this operation\&. For example: .IP .EX \[dq]Hello world!\[dq] | @base64 | \&., @base64d \-\-> \[dq]SGVsbG8gd29ybGQh\[dq] \[dq]Hello world!\[dq] .EE .PP \f[I]سازگاری\f[R] .RS In jaq, \f[CB]@base64d\f[R] only succeeds if its whole input is a valid Base64 string\&. In contrast, \f[CB]jq\f[R] accepts also strings where only a part is valid Base64, thus potentially leading to hidden data corruption\&. See \c .UR https://github.com/01mf02/jaq/issues/282 #282 .UE \c for a detailed discussion\&. .RE .SS \f[CB]@uri\f[R], \f[CB]@urid\f[R] .PP The filter \f[CB]@uri\f[R] applies \c .UR https://en.wikipedia.org/wiki/Percent-encoding percent\-encoding .UE \c to encode arbitrary data in a uniform resource identifier (URI)\&. The filter \f[CB]@urid\f[R] reverses this encoding\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]Hello, World!\[dq] | @uri \-\-> \[dq]Hello%2C%20World%21\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]Hello, World!\[dq] | @uri | @urid \-\-> \[dq]Hello, World!\[dq]\f[R] .RE .SS \f[CB]@sh\f[R] .PP The filter \f[CB]@sh\f[R] escapes data for constructing Unix command\-line prompts\&. It performs different things depending on its input type: .RS 2 .IP \[bu] 2 \f[CB]null\f[R], boolean, number: Convert to string via \f[CB]tostring\f[R]\&. .IP \[bu] 2 String: Replace occurrences of \f[CB]\[aq]\f[R] by \f[CB]\[aq]\[rs]\[aq]\[aq]\f[R] and surround by \f[CB]\[aq]\f[R]\&. .IP \[bu] 2 Array of scalars: Apply \f[CB]@sh\f[R] to elements and join the results with \f[CB]\[dq] \[dq]\f[R] as separator\&. .IP \[bu] 2 Fail for any other type of value\&. .RE .PP Examples: .RS 2 .IP \[bu] 2 \f[CB]null, true, 1 | @sh \-\-> \[dq]null\[dq] \[dq]true\[dq] \[dq]1\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]It\[aq]s green!\[dq] | @sh \-\-> \[dq]\[aq]It\[aq]\[rs]\[rs]\[aq]\[aq]s green!\[aq]\[dq]\f[R] .IP \[bu] 2 \f[CB][\[dq]jaq\[dq], \[dq]\-n\[dq], \[dq]\-\-arg\[dq], \[dq]slogan\[dq], \[dq]It\[aq]s green!\[dq], \[dq]$slogan\[dq]] | @sh \-\-> \[dq]\[aq]jaq\[aq] \[aq]\-n\[aq] \[aq]\-\-arg\[aq] \[aq]slogan\[aq] \[aq]It\[aq]\[rs]\[rs]\[aq]\[aq]s green!\[aq] \[aq]$slogan\[aq]\[dq]\f[R] .RE .SS "رشته‌های بایتی (BYTE STRINGS)" .SS \f[CB]tobytes\f[R] .PP The filter \f[CB]tobytes\f[R] converts its input to a byte string\&. Its output depends on the type of input: .RS 2 .IP \[bu] 2 Natural number in the range \f[CB]0\f[R] to \f[CB]255\f[R] (\f[CB]0xFF\f[R]): Yields a byte string with a single byte, e\&.g\&. \f[CB]0 | tobytes \-\-> b\[dq]\[rs]x00\[dq]\f[R]\&. .IP \[bu] 2 Text string: Yields a byte string containing the underlying bytes of the text string, e\&.g\&. \f[CB]\[dq]Hi\[dq] | tobytes \-\-> b\[dq]Hi\[dq]\f[R]\&. This takes constant time\&. .IP \[bu] 2 Byte string: Yields the byte string unchanged\&. .IP \[bu] 2 Array: Converts each element to a byte string and yields their concatenation, e\&.g\&. \f[CB][0, \[dq]Hi\[dq], [1, 255]] | tobytes \-\-> b\[dq]\[rs]x00Hi\[rs]x01\[rs]xFF\[dq]\f[R]\&. This is equivalent to \f[CB]map(tobytes) | add\f[R]\&. .IP \[bu] 2 Anything else: Yields an error\&. .RE .PP This is inspired by Erlang’s \f[CB]iolist_to_binary\f[R] function\&. .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] does not have byte strings and thus does not have \f[CB]tobytes\f[R]\&. \f[CB]fq\f[R], which has pioneered the \f[CB]tobytes\f[R] filter, has both\&. .RE .SS "سریال‌سازی و واسریال‌سازی (SERIALISATION & DESERIALISATION)" .PP The filters in this section read and write data in all formats supported by jaq\&. See the formats section for general information about how jaq interprets these formats\&. .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] supports only JSON, so it only implements the \f[CB]fromjson\f[R]/\f[CB]tojson\f[R] filters in this section\&. .RE .SS \f[CB]fromjson\f[R], \f[CB]tojson\f[R] .PP The filter \f[CB]fromjson\f[R] takes a string as input, parses it to JSON values and yields them\&. For example: .IP .EX \[dq]null true 0 \[rs]\[dq]foo\[rs]\[dq] [1] {\[rs]\[dq]foo\[rs]\[dq]: 1}\[dq] | fromjson \-\-> null true 0 \[dq]foo\[dq] [1] { \[dq]foo\[dq] : 1} .EE .PP The filter \f[CB]tojson\f[R] takes an arbitrary value and outputs a string containing its JSON representation\&. For example: .IP .EX \ [null,true,0, \[dq]foo\[dq] ,[1],{ \[dq]foo\[dq] :1}] | tojson \-\-> \[dq][null,true,0,\[rs]\[dq]foo\[rs]\[dq],[1],{\[rs]\[dq]foo\[rs]\[dq]:1}]\[dq] .EE .PP Note that \f[CB]tojson\f[R] behaves similarly to \f[CB]tostring\f[R], but when its input is a string, it will also encode it to JSON, instead of returning it unchanged; i\&.e\&. \f[CB]\[dq]Hi\[dq] | tojson \-\-> \[dq]\[rs]\[dq]Hi\[rs]\[dq]\[dq]\f[R]\&. .PP \f[I]سازگاری\f[R] .RS In \f[CB]jq\f[R], \f[CB]fromjson\f[R] yields an error when its input string contains multiple JSON values\&. Furthermore, in \f[CB]jaq\f[R], \f[CB]tojson | fromjson\f[R] is equivalent to identity (\f[CB]\&.\f[R]), whereas in \f[CB]jq\f[R], this is not the case, because \f[CB]nan | tojson | fromjson\f[R] yields \f[CB]null\f[R], not \f[CB]nan\f[R]\&. .RE .SS \f[CB]fromyaml\f[R], \f[CB]toyaml\f[R] .PP The filter \f[CB]fromyaml\f[R] takes a text string and parses it as sequence of YAML documents\&. It can yield an arbitrary number of outputs\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]\-\-\-\[rs]n 1 \[rs]n\&.\&.\&.\[rs]n\-\-\-\[rs]n 2 \[rs]n\&.\&.\&.\[dq] | fromyaml \-\-> 1 2\f[R] .IP \[bu] 2 \f[CB]\[dq]\[dq] | fromyaml \-\->\f[R] (no output) .RE .PP The filter \f[CB]toyaml\f[R] always yields exactly one output, namely a text string containing the current value encoded as YAML\&. .SS \f[CB]fromcbor\f[R], \f[CB]tocbor\f[R] .PP The filter \f[CB]fromcbor\f[R] takes a byte string and parses it as sequence of CBOR values\&. For example: .IP .EX [0, 1, 32, 64, 96, 128, 160, 244, 245, 246] | tobytes | fromcbor \-\-> 0 1 \-1 b\[dq]\[dq] \[dq]\[dq] [] {} false true null .EE .PP The filter \f[CB]tocbor\f[R] always yields exactly one output, namely a byte string containing the current value encoded as CBOR\&. .SS \f[CB]fromtoml\f[R], \f[CB]totoml\f[R] .PP The filter \f[CB]fromtoml\f[R] takes a text string and parses it as a single TOML document\&. It yields always one output, because every TOML document encodes exactly one value\&. For example: .IP .EX \[dq] [database]\[rs]n enabled = true\[rs]n ports = [ 8000, 8001, 8002 ]\[rs]n data = [ [\[rs]\[dq]delta\[rs]\[dq], \[rs]\[dq]phi\[rs]\[dq]], [3\&.14] ]\[rs]n temp_targets = { cpu = 79\&.5, case = 72\&.0 }\[rs]n \[dq] | fromtoml \-\-> {\[dq]database\[dq]: { \[dq]enabled\[dq]: true, \[dq]ports\[dq]: [8000,8001,8002], \[dq]data\[dq]: [[\[dq]delta\[dq], \[dq]phi\[dq]], [3\&.14]], \[dq]temp_targets\[dq]: {\[dq]cpu\[dq]: 79\&.5, \[dq]case\[dq]: 72\&.0} }} .EE .PP The filter \f[CB]totoml\f[R] fails if the input is not an object or the input contains any jaq value not supported by TOML\&. It converts invalid UTF\-8 sequences like CBOR\&. .SS \f[CB]fromxml\f[R], \f[CB]toxml\f[R] .PP The filter \f[CB]fromxml\f[R] takes a text string and parses it as sequence of XML tags\&. For example: .IP .EX \[dq] Hello HTML! \[dq] | fromxml \-\-> {\[dq]xmldecl\[dq]: {\[dq]version\[dq]: \[dq]1\&.0\[dq]}} {\[dq]t\[dq]: \[dq]html\[dq],\[dq]c\[dq]: [{ \[dq]t\[dq]: \[dq]body\[dq], \[dq]a\[dq]: {\[dq]xmlns\[dq]: \[dq]http://www\&.w3\&.org/1999/xhtml\[dq]}, \[dq]c\[dq]: [\[dq]Hello HTML!\[dq]] }]} .EE .PP The filter \f[CB]toxml\f[R] takes data produced in the format by \f[CB]fromxml\f[R] and yields a corresponding text string\&. .IP .EX [ {\[dq]xmldecl\[dq]: {\[dq]version\[dq]: \[dq]1\&.0\[dq]}}, {\[dq]t\[dq]: \[dq]html\[dq],\[dq]c\[dq]: [{ \[dq]t\[dq]: \[dq]body\[dq], \[dq]a\[dq]: {\[dq]xmlns\[dq]: \[dq]http://www\&.w3\&.org/1999/xhtml\[dq]}, \[dq]c\[dq]: [\[dq]Hello HTML!\[dq]] }]} ] | toxml \-\-> \[dq] Hello HTML! \[dq] .EE .SS \f[CB]fromcsv\f[R], \f[CB]tocsv\f[R] .PP The filter \f[CB]fromcsv\f[R] takes a string and yields each CSV row as an array of values\&. For example, \f[CB]\[dq]1,2\[rs]n3,4\[rs]n\[dq] | fromcsv \-\-> [1,2] [3,4]\f[R]\&. .PP Strings can be written quoted or unquoted\&. Inside quoted strings, \f[CB]\[dq]\[dq]\f[R] denotes a single quote (\f[CB]\[dq]\f[R])\&. .RS 2 .IP \[bu] 2 \f[CB]\[dq]plain,with space\[dq] | fromcsv \-\-> [\[dq]plain\[dq],\[dq]with space\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq]\[rs]\[dq]with,comma\[rs]\[dq]\[dq] | fromcsv \-\-> [\[dq]with,comma\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq]\[rs]\[dq]with\[rs]nnewline\[rs]\[dq]\[dq] | fromcsv \-\-> [\[dq]with\[rs]nnewline\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq]\[rs]\[dq]with\[rs]\[dq]\[rs]\[dq]quote\[rs]\[dq]\[dq] | fromcsv \-\-> [\[dq]with\[rs]\[dq]quote\[dq]]\f[R] .RE .PP The booleans \f[CB]true\f[R] and \f[CB]false\f[R] are returned as such\&. An empty field is returned as \f[CB]null\f[R]: .RS 2 .IP \[bu] 2 \f[CB]\[dq]true,,false\[dq] | fromcsv \-\-> [true, null, false]\f[R] .RE .PP Any field that is a valid XJON number is returned as such: .IP .EX \[dq]0,1,3\&.14,Infinity,+Infinity,\-Infinity\[dq] | fromcsv \-\-> [0,1,3\&.14,Infinity, Infinity,\-Infinity] .EE .PP Quoted booleans, numbers, or empty strings are always returned as strings: .PP \f[CB]\[dq]\[rs]\[dq]true\[rs]\[dq],\[rs]\[dq]\[rs]\[dq],\[rs]\[dq]false\[rs]\[dq],\[rs]\[dq]3\&.14\[rs]\[dq]\[dq] | fromcsv \-\-> [\[dq]true\[dq], \[dq]\[dq], \[dq]false\[dq], \[dq]3\&.14\[dq]]\f[R] .PP Rows can be terminated with LF (\f[CB]\[dq]\[rs]n\[dq]\f[R]) or CRLF (\f[CB]\[dq]\[rs]r\[rs]n\[dq]\f[R])\&. The last row may or may not be terminated with LF/CRLF\&. .RS 2 .IP \[bu] 2 \f[CB]\[dq]1,2\[rs]r\[rs]n3,4\[rs]n\[dq] | fromcsv \-\-> [1,2] [3,4]\f[R] .IP \[bu] 2 \f[CB]\[dq]1,2\[rs]n3,4\[rs]r\[rs]n\[dq] | fromcsv \-\-> [1,2] [3,4]\f[R] .IP \[bu] 2 \f[CB]\[dq]1,2\[rs]n3,4\[dq] | fromcsv \-\-> [1,2] [3,4]\f[R] .RE .PP A few extreme cases: .RS 2 .IP \[bu] 2 \f[CB]\[dq]\[dq] | fromcsv \-\-> \f[R] (no output) .IP \[bu] 2 \f[CB]\[dq]\[rs]n\[dq] | fromcsv \-\-> [null]\f[R] (empty lines are interpreted as \f[CB]null\f[R]) .IP \[bu] 2 \f[CB]\[dq],\[dq] | fromcsv \-\-> [null, null]\f[R] .RE .PP The filter \f[CB]tocsv\f[R] takes an array of scalars\&. It transforms each array element depending on its type: .RS 2 .IP \[bu] 2 \f[CB]null\f[R]: Yield \f[CB]\[dq]\[dq]\f[R]\&. .IP \[bu] 2 Boolean, number: Transform it via \f[CB]tostring\f[R]\&. .IP \[bu] 2 String: Replace occurrences of \f[CB]\[dq]\f[R] by \f[CB]\[dq]\[dq]\f[R] and surround by \f[CB]\[dq]\f[R]\&. .IP \[bu] 2 Fail for any other type of value\&. .RE .PP Finally, the filter joins the transformed elements with \f[CB]\[dq],\[dq]\f[R] as separator\&. For example: .IP .EX [true, null, false, 1, \[dq]Give me \[rs]\[dq]quotes\[rs]\[dq], or die\[dq]] | tocsv \-\-> \[dq]true,,false,1,\[rs]\[dq]Give me \[rs]\[dq]\[rs]\[dq]quotes\[rs]\[dq]\[rs]\[dq], or die\[rs]\[dq]\[dq] .EE .SS \f[CB]fromtsv\f[R], \f[CB]totsv\f[R] .PP The filter \f[CB]fromtsv\f[R] takes a string and yields each TSV row as an array of values\&. For example, \f[CB]\[dq]1\[rs]t2\[rs]n3\[rs]t4\[rs]n\[dq] | fromtsv \-\-> [1,2] [3,4]\f[R]\&. .PP The filter \f[CB]totsv\f[R] is similar to \f[CB]tocsv\f[R], with the following differences: .RS 2 .IP \[bu] 2 In strings, the characters \f[CB]\[aq]\[rs]n\[aq]\f[R], \f[CB]\[aq]\[rs]r\[aq]\f[R], \f[CB]\[aq]\[rs]t\[aq]\f[R], \f[CB]\[aq]\[rs]\[aq]\f[R], and \f[CB]\[aq]\[rs]u0000\[aq]\f[R] are replaced by strings \f[CB]\[dq]\[rs]\[rs]n\[dq]\f[R], \f[CB]\[dq]\[rs]\[rs]r\[dq]\f[R], \f[CB]\[dq]\[rs]\[rs]t\[dq]\f[R], \f[CB]\[dq]\[rs]\[rs]\[rs]\[rs]\[dq]\f[R], \f[CB]\[dq]\[rs]\[rs]0\[dq]\f[R]\&. (In raw output, these look like \f[CB]\[rs]n\f[R], \f[CB]\[rs]r\f[R], \f[CB]\[rs]t\f[R], \f[CB]\[rs]\[rs]\f[R], and \f[CB]\[rs]0\f[R]\&.) The result is not surrounded by \f[CB]\[dq]\f[R]\&. .IP \[bu] 2 The transformed elements are joined with \f[CB]\[rs]t\f[R] (tabulator)\&. .RE .PP For example: .IP .EX [true, null, false, 1, \[dq]hello \[rs]\[dq]quotes\[rs]\[dq] and \[rs]n\[rs]r\[rs]t\[rs]\[rs] escapes\[dq]] | totsv \-\-> \[dq]true\[rs]t\[rs]tfalse\[rs]t1\[rs]thello \[rs]\[dq]quotes\[rs]\[dq] and \[rs]\[rs]n\[rs]\[rs]r\[rs]\[rs]t\[rs]\[rs]\[rs]\[rs] escapes\[dq] .EE .PP TSV strings are always unquoted\&. Encode control characters using \f[CB]\[rs]0\f[R], \f[CB]\[rs]t\f[R], \f[CB]\[rs]r\f[R], \f[CB]\[rs]n\f[R], and \f[CB]\[rs]\[rs]\f[R]: .RS 2 .IP \[bu] 2 \f[CB]\[dq]with\[rs]\[rs]0NUL\[dq] | fromtsv \-\-> [\[dq]with\[rs]u0000NUL\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq]with\[rs]\[rs]tTAB\[dq] | fromtsv \-\-> [\[dq]with\[rs]tTAB\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq]with\[rs]\[rs]rCR\[dq] | fromtsv \-\-> [\[dq]with\[rs]rCR\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq]with\[rs]\[rs]nLF\[dq] | fromtsv \-\-> [\[dq]with\[rs]nLF\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq]with\[rs]\[rs]\[rs]\[rs]\[dq] | fromtsv \-\-> [\[dq]with\[rs]\[rs]\[dq]]\f[R] .RE .SS "تاریخ و زمان (DATE & TIME)" .PP The filters in this section serve to convert between different time formats, such as: .RS 2 .IP \[bu] 2 Unix epoch: Marks a point in time by the number of seconds passed since January 1, 1970 00:00:00 (UTC)\&. You can obtain the current time as Unix epoch via \f[CB]now\f[R]\&. .IP \[bu] 2 ISO\-8601 datetime string: Represents a date, a time, and a time zone as a string, such as \f[CB]\[dq]1970\-01\-01T00:00:00Z\[dq]\f[R] (corresponding to Unix epoch \f[CB]0\f[R])\&. .IP \[bu] 2 “Broken down time” (BDT) array: Represents a date and a time as an array of the shape \f[CB][year, month, day, hour, minute, second, weekday, yearday]\f[R]\&. All components are integers, except for \f[CB]second\f[R], which may be a floating\-point number\&. The \f[CB]month\f[R] is counted from \f[CB]0\f[R], the \f[CB]weekday\f[R] is counted from Sunday (which is \f[CB]0\f[R]), and the \f[CB]yearday\f[R] is the day in the year counted from \f[CB]0\f[R]\&. When a BDT array is used as input, only the first six components are considered\&. .RE .PP You can convert between these representations via: .RS 2 .IP \[bu] 2 Unix epoch from/to ISO 8601: \f[CB]fromdate\f[R], \f[CB]todate\f[R] .IP \[bu] 2 BDT to Unix epoch: \f[CB]mktime\f[R] .IP \[bu] 2 Unix epoch to BDT: \f[CB]gmtime, localtime\f[R] .IP \[bu] 2 Unix epoch or BDT from/to custom string: \f[CB]strptime\f[R], \f[CB]strftime\f[R], \f[CB]strflocaltime\f[R] .RE .PP As example, let us consider the time where the Hill Valley courthouse’s clock tower was struck by lightning, namely \c .UR https://en.wikipedia.org/wiki/Hill_Valley_(Back_to_the_Future%29#Town_square Saturday, November 12, 1955, at 10:04 p\&.m\&. PST .UE \c \&. The corresponding date can be written in ISO 8601 as \f[CB]\[dq]1955\-11\-12T10:04:00\-08:00\[dq]\f[R]\&. We can convert that to a Unix epoch and from there to a (UTC) BDT via: .IP .EX \[dq]1955\-11\-12T22:04:00\-08:00\[dq] | fromdate | gmtime \-\-> [ 1955, 10, 13, 6, 4, 0, 0, 316 ] .EE .PP We can infer that at this moment, in UTC it was November 13 (the BDT month is \f[CB]10\f[R] and not \f[CB]11\f[R], because BDT months are counted from \f[CB]0\f[R]), at 06:04:00\&. Furthermore, that day was a Sunday (because the \f[CB]weekday\f[R] is \f[CB]0\f[R]), which was the \f[CB]316\f[R]\-th day of the year (where \f[CB]0\f[R] is the first day)\&. .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] does not allow time zone information in ISO 8601 datetime strings\&. .RE .SS \f[CB]fromdate\f[R], \f[CB]todate\f[R], \f[CB]fromdateiso8601\f[R], \f[CB]todateiso8601\f[R] .PP These filters convert between Unix time and ISO\-8601 timestamps\&. .PP For example, the \c .UR https://en.wikipedia.org/wiki/Apollo_13#Accident Apollo 13 accident .UE \c happened at 03:08 UTC on April 14, 1970\&. Its corresponding Unix time is \f[CB]\[dq]1970\-04\-14T03:08:00Z\[dq] | fromdate \-\-> 8910480\f[R]\&. We can get back the ISO\-8601 timestamp via \f[CB]8910480 | todate \-\-> \[dq]1970\-04\-14T03:08:00Z\[dq]\f[R]\&. .PP These filters can handle floating\-point numbers, e\&.g\&. \f[CB]0\&.123456 | todate \-\-> \[dq]1970\-01\-01T00:00:00\&.123456Z\[dq]\f[R] and \f[CB]\[dq]1970\-01\-01T00:00:00\&.123456Z\[dq] | fromdate \-\-> 0\&.123456\f[R]\&. In particular, \f[CB]fromdate\f[R] yields a floating\-point number if the time cannot be represented losslessly as an integer\&. .PP The filters \f[CB]fromdateiso8601\f[R] and \f[CB]todateiso8601\f[R] are synonyms of \f[CB]fromdate\f[R] and \f[CB]todate\f[R], respectively\&. .SS \f[CB]strftime($fmt)\f[R], \f[CB]strflocaltime($fmt)\f[R] .PP The filters \f[CB]strftime($fmt)\f[R] and \f[CB]strflocaltime($fmt)\f[R] take as input either a number that is interpreted as Unix epoch, or a BDT array\&. The filters yield a string representation of the input time, using the format \f[CB]$fmt\f[R]\&. .PP If the input is a Unix epoch, both \f[CB]strftime\f[R] and \f[CB]strflocaltime\f[R] interpret it as UTC timestamp\&. If the input is a BDT array, then \f[CB]strftime\f[R] interprets input as UTC and \f[CB]strflocaltime\f[R] interprets input as user local time\&. \f[CB]strftime\f[R] outputs the time as UTC and \f[CB]strflocaltime\f[R] outputs the time as user local time\&. .PP For example, if the user is in the CET zone (+0100): .RS 2 .IP \[bu] 2 \f[CB]0 | strftime(\[dq]%T %z (%Z)\[dq]) \-\-> \[dq]00:00:00 +0000 (UTC)\[dq]\f[R] .IP \[bu] 2 \f[CB][1970, 0, 1, 0, 0, 0] | strftime(\[dq]%T %z (%Z)\[dq]) \-\-> \[dq]00:00:00 +0000 (UTC)\[dq]\f[R] .IP \[bu] 2 \f[CB]0 | strflocaltime(\[dq]%T %z (%Z)\[dq])\f[R] yields \f[CB]\[dq]01:00:00 +0100 (CET)\[dq]\f[R] .IP \[bu] 2 \f[CB][1970, 0, 1, 0, 0, 0] | strflocaltime(\[dq]%T %z (%Z)\[dq])\f[R] yields \f[CB]\[dq]00:00:00 +0100 (CET)\[dq]\f[R] .RE .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] prints \f[CB]GMT\f[R] instead of \f[CB]UTC\f[R] in the examples above; however, GMT is not the same as UTC\&. .RE .SS \f[CB]strptime($fmt)\f[R] .PP The filter \f[CB]strptime($fmt)\f[R] takes a string and parses it using the format \f[CB]$fmt\f[R], yielding a BDT array\&. If no time zone is inferred from the input (e\&.g\&. via \f[CB]%Z\f[R]), it is assumed to be UTC\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]1970\-01\-01 00:00:00\[dq] | strptime(\[dq]%F %T\[dq]) \-\-> [1970, 0, 1, 0, 0, 0, 4, 0]\f[R] .IP \[bu] 2 \f[CB]\[dq]1970\-01\-01 00:00:00 Europe/Vienna\[dq] | strptime(\[dq]%F %T %Q\[dq]) \-\-> [1970, 0, 1, 0, 0, 0, 4, 0]\f[R] .RE .SS \f[CB]gmtime\f[R], \f[CB]localtime\f[R] .PP The filters \f[CB]gmtime\f[R] and \f[CB]localtime\f[R] take a Unix epoch as input and yield a corresponding BDT array, containing the time in UTC (\f[CB]gmtime\f[R]) or in the user local time (\f[CB]localtime\f[R])\&. .PP For example, if the user is in the CET zone (+0100): .RS 2 .IP \[bu] 2 \f[CB]0 | gmtime \-\-> [1970, 0, 1, 0, 0, 0, 4, 0]\f[R] .IP \[bu] 2 \f[CB]0 | localtime\f[R] yields \f[CB][1970, 0, 1, 1, 0, 0, 4, 0]\f[R] .RE .SS \f[CB]mktime\f[R] .PP The filter \f[CB]mktime\f[R] takes a BDT array that is assumed to be in UTC, and yields the corresponding Unix epoch\&. For example, \f[CB][1970, 0, 1, 0, 0, 0] | mktime \-\-> 0\f[R]\&. .SS "عبارت‌های منظم (REGULAR EXPRESSIONS)" .PP All the filters in this section, such as \f[CB]test\f[R], take a string as input and fail if they receive any other type of value\&. Furthermore, they all take two string arguments, namely the regular expression \f[CB]$re\f[R] and the \f[CB]$flags\f[R] that determine how the regular expression is interpreted\&. Omitting \f[CB]$flags\f[R] is equivalent to passing \f[CB]\[dq]\[dq]\f[R] as \f[CB]$flags\f[R]\&. For example, \f[CB]test($re)\f[R] is equivalent to \f[CB]test($re; \[dq]\[dq])\f[R]\&. .PP The supported flags are: .RS 2 .IP \[bu] 2 \f[CB]g\f[R]: global search .IP \[bu] 2 \f[CB]n\f[R]: ignore empty matches .IP \[bu] 2 \f[CB]i\f[R]: case\-insensitive .IP \[bu] 2 \f[CB]m\f[R]: multi\-line mode: \f[CB]^\f[R] and \f[CB]$\f[R] match begin/end of line .IP \[bu] 2 \f[CB]s\f[R]: single\-line mode: allow \f[CB]\&.\f[R] to match \f[CB]\[rs]n\f[R] .IP \[bu] 2 \f[CB]l\f[R]: greedy .IP \[bu] 2 \f[CB]x\f[R]: extended mode: ignore whitespace and allow line comments (starting with \f[CB]#\f[R]) .RE .PP \f[I]سازگاری\f[R] .RS jaq uses the \c .UR https://docs.rs/regex-lite \f[CB]regex\-lite\f[R] .UE \c crate to compile and run regular expressions (regexes)\&. See the crate documentation for a description of the supported regex syntax\&. .RE .SS \f[CB]test\f[R] .PP The filter \f[CB]test\f[R] yields \f[CB]true\f[R] if some part of the input matches the regular expression, else \f[CB]false\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]jaq v3\&.0\[dq] | test(\[dq]v[0\-9]+\[rs]\[rs]\&.[0\-9]+\[dq]) \-\-> true\f[R] .IP \[bu] 2 \f[CB]\[dq]jaq V3\&.0\[dq] | test(\[dq]v[0\-9]+\[rs]\[rs]\&.[0\-9]+\[dq]) \-\-> false\f[R] .IP \[bu] 2 \f[CB]\[dq]jaq V3\&.0\[dq] | test(\[dq]v[0\-9]+\[rs]\[rs]\&.[0\-9]+\[dq]; \[dq]i\[dq]) \-\-> true\f[R] .RE .SS \f[CB]scan\f[R] .PP The filter \f[CB]scan\f[R] yields all parts of the input that match the regular expression\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]v2\&.0, v3\&.0\[dq] | scan(\[dq]v[0\-9]+\[rs]\[rs]\&.[0\-9]+\[dq] ) \-\-> \[dq]v2\&.0\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]v2\&.0, v3\&.0\[dq] | scan(\[dq]v[0\-9]+\[rs]\[rs]\&.[0\-9]+\[dq]; \[dq]g\[dq]) \-\-> \[dq]v2\&.0\[dq] \[dq]v3\&.0\[dq]\f[R] .IP \[bu] 2 \f[CB]\[dq]V2\&.0\[dq] | scan(\[dq]v[0\-9]+\[rs]\[rs]\&.[0\-9]+\[dq]) \-\->\f[R] (no output) .RE .SS \f[CB]match\f[R] .PP The filter \f[CB]match\f[R] yields an object for every part of the input that matches the regular expression, containing: .RS 2 .IP \[bu] 2 \f[CB]\[dq]offset\[dq]\f[R]: the character index of the start of the match .IP \[bu] 2 \f[CB]\[dq]length\[dq]\f[R]: the number of characters of the match .IP \[bu] 2 \f[CB]\[dq]string\[dq]\f[R]: the contents of the match .IP \[bu] 2 \f[CB]\[dq]captures\[dq]\f[R]: an array with an object for every capture group, containing: .RS 2 .IP \[bu] 2 \f[CB]\[dq]offset\[dq]\f[R], .IP \[bu] 2 \f[CB]\[dq]length\[dq]\f[R], .IP \[bu] 2 \f[CB]\[dq]string\[dq]\f[R]: as above, but for the capture group instead of the whole match .IP \[bu] 2 \f[CB]\[dq]name\[dq]\f[R]: the name of the capture group if it has one, else this key is omitted .RE .RE .PP Example: .IP .EX \[dq]v2\&.0, v3\&.0\[dq] | match(\[dq]v(?[0\-9]+)\[rs]\[rs]\&.([0\-9]+)\[dq]; \[dq]g\[dq]) \-\-> { \[dq]offset\[dq]: 0, \[dq]length\[dq]: 4, \[dq]string\[dq]: \[dq]v2\&.0\[dq], \[dq]captures\[dq]: [ { \[dq]offset\[dq]: 1, \[dq]length\[dq]: 1, \[dq]string\[dq]: \[dq]2\[dq], \[dq]name\[dq]: \[dq]maj\[dq] }, { \[dq]offset\[dq]: 3, \[dq]length\[dq]: 1, \[dq]string\[dq]: \[dq]0\[dq] } ] } { \[dq]offset\[dq]: 6, \[dq]length\[dq]: 4, \[dq]string\[dq]: \[dq]v3\&.0\[dq], \[dq]captures\[dq]: [ { \[dq]offset\[dq]: 7, \[dq]length\[dq]: 1, \[dq]string\[dq]: \[dq]3\[dq], \[dq]name\[dq]: \[dq]maj\[dq] }, { \[dq]offset\[dq]: 9, \[dq]length\[dq]: 1, \[dq]string\[dq]: \[dq]0\[dq] } ] } .EE .SS \f[CB]capture\f[R] .PP The filter \f[CB]capture\f[R] yields an object for every part of the input that matches the regular expression, containing for each named capture group an entry with the group name as key and its matched string as value\&. .PP Example: .IP .EX \[dq]v2\&.0, v3\&.0\[dq] | capture(\[dq]v(?[0\-9]+)\[rs]\[rs]\&.(?[0\-9]+)\[dq]; \[dq]g\[dq]) \-\-> { \[dq]maj\[dq]: \[dq]2\[dq], \[dq]min\[dq]: \[dq]0\[dq] } { \[dq]maj\[dq]: \[dq]3\[dq], \[dq]min\[dq]: \[dq]0\[dq] } .EE .SS \f[CB]split\f[R], \f[CB]splits\f[R] .PP The filter \f[CB]split($re; $flags)\f[R] yields an array of those parts of the input string that do \f[B]not\f[R] match the regular expression \f[CB]$re\f[R]\&. For example: .RS 2 .IP \[bu] 2 \f[CB]\[dq]Here be\[rs]tspaces\[dq] | split(\[dq]\[rs]\[rs]s\[dq] ; \[dq]\[dq]) \-\-> [\[dq]Here\[dq], \[dq]be\[dq], \[dq]spaces\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq] More\[rs]n\[rs]n\[dq] | split(\[dq]\[rs]\[rs]s+\[dq]; \[dq]\[dq]) \-\-> [\[dq]\[dq], \[dq]More\[dq], \[dq]\[dq]]\f[R] .IP \[bu] 2 \f[CB]\[dq]\[dq] | split(\[dq]\[rs]\[rs]s\[dq] ; \[dq]\[dq]) \-\-> [\[dq]\[dq]]\f[R] .RE .PP Note that \f[CB]split($re; $flags)\f[R] is equivalent to \f[CB]split($re; \[dq]g\[dq] + $flags)\f[R], meaning that the string is split not only by the first match, but by all matches\&. Furthermore, unlike all other filters in this section, \f[CB]split($s)\f[R] is \f[B]not\f[R] equivalent to \f[CB]split($s; $flags)\f[R], because \f[CB]split($s)\f[R] splits a string by a separator that is \f[B]not\f[R] interpreted as regular expression; see \f[CB]split\f[R]\&. .PP The filter \f[CB]splits($re; $flags)\f[R] yields the elements of the array yielded by \f[CB]split($re; $flags)\f[R]\&. For example, \f[CB]\[dq]Here be\[rs]tspaces\[dq] | splits(\[dq]\[rs]\[rs]s\[dq]) \-\-> \[dq]Here\[dq] \[dq]be\[dq] \[dq]spaces\[dq]\f[R]\&. The filter \f[CB]splits($re)\f[R] is equivalent to \f[CB]splits($re; \[dq]\[dq])\f[R]\&. .SS \f[CB]sub\f[R], \f[CB]gsub\f[R] .PP The filter \f[CB]sub($re; f; $flags)\f[R] replaces all parts of the input string that match \f[CB]$re\f[R] by the output of \f[CB]f\f[R]\&. Here, \f[CB]f\f[R] receives an object as returned by \f[CB]capture\f[R]; that is, for every named capture group, it contains its name as key and its matched string as value\&. .PP For example: .IP .EX \[dq]Mr\&. 高橋 & Mrs\&. 嵯峨\[dq] | sub(\[dq](?(Mr|Ms|Mrs)\[rs]\[rs]\&.) (?<name>\[rs]\[rs]S+)\[dq]; \[dq]\[rs](\&.name) (\[rs](\&.title))\[dq]; \[dq]g\[dq]) \-\-> \[dq]高橋 (Mr\&.) & 嵯峨 (Mrs\&.)\[dq] .EE .PP When the filter \f[CB]f\f[R] yields multiple outputs, then all potential combinations are output\&. For example: .IP .EX \[dq]Thanks, fine\&.\[dq] | sub(\[dq](?<word>\[rs]\[rs]w+)\[dq]; \&.word, (\&.word | ascii_upcase); \[dq]g\[dq]) \-\-> \[dq]Thanks, fine\&.\[dq] \[dq]Thanks, FINE\&.\[dq] \[dq]THANKS, fine\&.\[dq] \[dq]THANKS, FINE\&.\[dq] .EE .PP We have following short forms: .RS 2 .IP \[bu] 2 The filter \f[CB]gsub($re; f; $flags)\f[R] is equivalent to \f[CB]sub($re; f; \[dq]g\[dq] + $flags)\f[R]\&. .IP \[bu] 2 The filter \f[CB]gsub($re; f)\f[R] is equivalent to \f[CB]gsub($re; f; \[dq]\[dq])\f[R]\&. .IP \[bu] 2 The filter \f[CB]sub($re; f)\f[R] is equivalent to \f[CB]sub($re; f; \[dq]\[dq])\f[R]\&. .RE .SS "ورودی/خروجی (I/O)" .PP This section contains filters that interact with the system\&. These filters may yield different outputs when given equal inputs\&. .SS \f[CB]input\f[R], \f[CB]inputs\f[R] .PP The filter \f[CB]inputs\f[R] yields all the inputs in the current input file\&. For example: .IP .EX $ echo 1 2 3 | jaq \-nc \[aq][inputs]\[aq] [1,2,3] .EE .PP This can be useful to fold over large (potentially infinite) amounts of values; for example, to create a cumulative sum over all input integers, you can use \f[CB]jaq \-n \[aq]foreach inputs as $x (0; \&.+$x)\[aq]\f[R]\&. .PP The filter \f[CB]input\f[R] yields the next input in the current input file\&. .PP \f[I]سازگاری\f[R] .RS When there is no more input value left, in \f[CB]jq\f[R], \f[CB]input\f[R] yields an error, whereas in jaq, it yields no output value\&. That is, in jaq, \f[CB]input\f[R] is equivalent to \f[CB]first(inputs)\f[R]\&. .RE .SS \f[CB]debug\f[R], \f[CB]debug(f)\f[R] .PP The filter \f[CB]debug(f)\f[R] prints a debug message for every output of \f[CB]f\f[R] to the standard error stream (stderr), then yields its input\&. For example: .IP .EX $ jaq \-n \[aq]0 | debug(1, 2)\[aq] [\[dq]DEBUG:\[dq], 1] [\[dq]DEBUG:\[dq], 2] 0 .EE .PP The filter \f[CB]debug\f[R] is equivalent to \f[CB]debug(\&.)\f[R]\&. .SS \f[CB]stderr\f[R] .PP The filter \f[CB]stderr\f[R] prints its input to the standard error stream in raw and compact mode without newline\&. It then yields its input\&. .IP .EX $ jaq \-n \[aq]\[dq]Hi\[dq] | stderr\[aq] Hi\[dq]Hi\[dq] .EE .SS \f[CB]halt\f[R], \f[CB]halt($exit_code)\f[R] .PP The filter \f[CB]halt($exit_code)\f[R] terminates jaq with the given exit code\&. .PP The filter \f[CB]halt\f[R] terminates jaq with exit code 0\&. .IP .EX $ jaq \-n \[aq]1, halt , 2\[aq] 1 $ jaq \-n \[aq]1, halt(42), 2\[aq]; echo $? 1 42 .EE .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] does not implement \f[CB]halt($exit_code)\f[R], only \f[CB]halt\f[R]\&. .RE .SS \f[CB]halt_error\f[R], \f[CB]halt_error($exit_code)\f[R] .PP The filter \f[CB]halt_error($exit_code)\f[R] prints its input via \f[CB]stderr\f[R]\&. It then quits the jaq process with the given exit code\&. .PP The filter \f[CB]halt_error\f[R] is equivalent to \f[CB]halt_error(5)\f[R]\&. .IP .EX $ jaq \-n \[aq]\[dq]Hi!\[dq] | halt_error(42)\[aq]; echo $? Hi!42 $ jaq \-n \[aq]\[dq]Hi!\[dq] | halt_error \[aq]; echo $? Hi!5 .EE .PP \f[I]سازگاری\f[R] .RS \f[CB]jq\f[R] prints a newline after the input if it is not a string\&. .RE .SS \f[CB]now\f[R] .PP This filter yields the Unix epoch as floating\-point number\&. .IP .EX $ date +%s | jaq \[aq]now \- \&. as $dt | 0 <= $dt and $dt <= 2\[aq] true .EE .SS \f[CB]$ENV\f[R], \f[CB]env\f[R] .PP The variable \f[CB]$ENV\f[R] holds an object that contains an entry for every environment variable, where the key is the name of the variable and the value is its value\&. For example, \f[CB]{\[dq]EDITOR\[dq]: \[dq]vim\[dq], \[dq]SHELL\[dq]: \[dq]/usr/bin/bash\[dq]}\f[R]\&. .IP .EX $ MYFLAG=42 jaq \-n \[aq]$ENV\&.MYFLAG\[aq] \[dq]42\[dq] .EE .PP The filter \f[CB]env\f[R] is equivalent to \f[CB]$ENV\f[R]\&. .SS \f[CB]input_filename\f[R] .PP The filter \f[CB]input_filename\f[R] returns the name of the file currently read, or \f[CB]\[dq]<stdin>\[dq]\f[R] if standard input is currently read\&. .IP .EX $ jaq \-\-slurp \[aq]input_filename\[aq] \[dq]examples/benches\&.json\[dq] \[dq]examples/benches\&.json\[dq] $ echo 0 | jaq \[aq]input_filename\[aq] \[dq]<stdin>\[dq] .EE .PP \f[I]سازگاری\f[R] .RS In jq, this filter returns the name of the file most recently read from\&. This can lead to subtle differences compared to jaq\&. For example: .IP .EX $ echo 0 | jaq \-\-null\-input \[aq](\&., inputs) | input_filename\[aq] \[dq]<stdin>\[dq] \[dq]<stdin>\[dq] .EE .PP Here, jq yields \f[CB]null \[dq]<stdin>\[dq]\f[R]\&. Why? When executing the filter \f[CB]\&.\f[R], jq did not read any input, so \f[CB]input_filename\f[R] returns \f[CB]null\f[R]\&. However, when executing \f[CB]inputs\f[R], jq starts reading from standard input, so \f[CB]input_filename\f[R] returns \f[CB]\[dq]<stdin>\[dq]\f[R]\&. .PP In contrast, jaq considers a file as being read even when it has only been opened\&. .RE .SS \f[CB]repl\f[R] .PP The filter \f[CB]repl\f[R] starts an interactive REPL (read\-eval\-print\-loop)\&. You can nest calls to \f[CB]repl\f[R]; that is, you can run \f[CB]repl\f[R] from inside a \f[CB]repl\f[R]\&. Use CTRL\-D to exit a REPL\&. .PP This filter yields no output\&. It writes its history to a file \f[CB]jaq\-history\f[R] in the user’s cache directory\&. .PP \f[I]سازگاری\f[R] .RS This filter has been inspired by \f[CB]fq\f[R]’s \f[CB]repl\f[R] filter\&. However, unlike \f[CB]fq\f[R], jaq does not require to be started with the \f[CB]\-\-repl\f[R] flag, and it allows calls to \f[CB]repl\f[R] anywhere in a filter, not only last in the pipeline\&. .PP \f[CB]jq\f[R] does not have this filter\&. .RE .SS "پشتیبانی‌نشده (UNSUPPORTED)" .PP This section lists filters present in \f[CB]jq\f[R], but not in jaq\&. .RS 2 .IP \[bu] 2 \c .UR https://jqlang.org/manual/#$__loc__ \f[CB]$__loc__\f[R] .UE \c .IP \[bu] 2 \f[CB]modulemeta\f[R] .IP \[bu] 2 \c .UR https://jqlang.org/manual/#have_literal_numbers \f[CB]have_literal_numbers\f[R] .UE \c .IP \[bu] 2 \c .UR https://jqlang.org/manual/#have_decnum \f[CB]have_decnum\f[R] .UE \c .IP \[bu] 2 \c .UR https://jqlang.org/manual/#$jq_build_configuration \f[CB]$JQ_BUILD_CONFIGURATION\f[R] .UE \c .IP \[bu] 2 \c .UR https://jqlang.org/manual/#builtins \f[CB]builtins\f[R] .UE \c .IP \[bu] 2 \c .UR https://jqlang.org/manual/#input_line_number \f[CB]input_line_number\f[R] .UE \c .RE .PP jaq supports none of jq’s \c .UR https://jqlang.org/manual/#sql-style-operators SQL\-style operators .UE \c , mostly for aesthetic reasons (uppercase\-names) and because jq is not SQL: .RS 2 .IP \[bu] 2 \f[CB]INDEX\f[R] .IP \[bu] 2 \f[CB]JOIN\f[R] .IP \[bu] 2 \f[CB]IN\f[R] .RE .PP jaq does not support \f[CB]jq\f[R]’s \c .UR https://jqlang.org/manual/#streaming \f[CB]\-\-stream\f[R] .UE \c option; therefore, it also does not implement the related filters: .RS 2 .IP \[bu] 2 \f[CB]truncate_stream\f[R] .IP \[bu] 2 \f[CB]fromstream\f[R] .IP \[bu] 2 \f[CB]tostream\f[R] .RE .SH "ویژگی‌های پیشرفته (ADVANCED FEATURES)" .SS "انتساب‌ها (ASSIGNMENTS)" .PP دستور jq امکان انتساب‌هایی به شکل \f[CB]p |= f\f[R] را فراهم می‌کند، که در آن \f[CB]p\f[R] یک فیلتر دلخواه است\&. این ویژگی انتساب‌ها در jq را در مقایسه با سایر زبان‌ها به طور منحصر به فردی قدرتمند می‌سازد\&. برای نمونه، برنامه‌ای از راهنمای jq که ذهن مرا شگفت‌زده کرد، دستور زیر بود: .IP .EX (\&.posts[] | select(\&.author == \[dq]stedolan\[dq]) | \&.comments) += [\[dq]terrible\&.\[dq]] .EE .PP این فیلتر روی تمام پست‌ها پیمایش می‌کند، پست‌هایی را که نویسنده آن‌ها “stedolan” است انتخاب می‌کند، کامنت‌های آن‌ها را می‌گیرد، و یک نظر نه چندان خوشایند به آن‌ها اضافه می‌کند\&. (این بازتاب‌دهنده نظر من درباره استیون دولان نیست — به نظر من او در خلق jq کار فوق‌العاده‌ای انجام داده است\&.) .PP دستور jaq و برنامه \f[CB]jq\f[R] دو رویکرد متفاوت را برای اجرای انتساب‌ها دنبال می‌کنند: .RS 2 .IP \[bu] 2 \f[B]مبتنی بر مسیر (Path\-based)\f[R]: در \f[CB]jq\f[R]، انتساب \f[CB]p |= f\f[R] مسیرها را به تمام مقادیری که با \f[CB]p\f[R] مطابقت دارند می‌سازد و فیلتر \f[CB]f\f[R] را روی این مقادیر اعمال می‌کند\&. .IP \[bu] 2 \f[B]بدون مسیر (Pathless)\f[R]: در jaq، یک انتساب \f[CB]p |= f\f[R] به یک فیلتر متفاوت تبدیل می‌شود که هیچ مسیری نمی‌سازد\&. .RE .PP برای نمونه، به‌روزرسانی زیر را در نظر بگیرید: \f[CB][1, 2, 3] | \&.[] |= \&.+1 \-\-> [2, 3, 4]\f[R]: هنگامی که \f[CB]jq\f[R] این دستور را اجرا می‌کند، عبارت \f[CB][1, 2, 3] | path(\&.[]) \-\-> [0] [1] [2]\f[R] را محاسبه کرده و \f[CB]\&.+1\f[R] را روی هر مقدار در این مسیرها اعمال می‌کند\&. از سوی دیگر، jaq این به‌روزرسانی را به صورت زیر تبدیل می‌کند: \f[CB][1, 2, 3] | [\&.[] | \&.+1] \-\-> [2, 3, 4]\f[R] — این انتساب شامل ساخت هیچ مسیری نمی‌شود\&. .PP خوشبختانه، همانند مثال فوق، در بیشتر موارد نتیجه هر دو رویکرد یکسان است\&. بخش‌های زیر این دو رویکرد را با جزئیات بیشتر توضیح می‌دهند، و بیان می‌کنند که چگونه می‌توان به‌روزرسانی‌هایی نوشت که در هر دو مفسر \f[CB]jq\f[R] و jaq رفتار یکسانی داشته باشند\&. .SS "مبتنی بر مسیر (Path\-based)" .PP مدل به‌روزرسانی مبتنی بر مسیر که توسط \f[CB]jq\f[R] استفاده می‌شود، \f[CB]p |= u\f[R] را با ابتدا جمع‌آوری مسیرهای متناظر با \f[CB]p\f[R]، و سپس به‌روزرسانی ورودی در این مسیرها با \f[CB]u\f[R] اجرا می‌کند\&. ما می‌توانیم این رفتار را با \f[CB]getpath(path(p)) |= u\f[R] تقریبی شبیه‌سازی کنیم — رفتار واقعی به‌روزرسانی در \f[CB]jq\f[R] بسیار پیچیده‌تر است، تنها به صورت مختصر مستند شده است، و بین نسخه‌های جزئی دچار تغییرات ناسازگار با گذشته شده است\&. .PP فیلترهای \f[CB]reduce\f[R] / \f[CB]foreach\f[R] هر دو در jaq بر اساس فیلترهای ساده‌تر \f[CB]f\f[R] تعریف شده‌اند که \f[CB]path(f)\f[R] می‌تواند آن‌ها را ارزیابی کند\&. بنابراین، در jaq، می‌توانید از \f[CB]reduce\f[R] / \f[CB]foreach\f[R] درون \f[CB]path(f)\f[R] و همچنین در سمت چپ به‌روزرسانی‌ها استفاده کنید\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB][{a: 1}] | path(reduce (0, \[dq]a\[dq]) as $i (\&.; \&.[$i])) \-\-> [0, \[dq]a\[dq]]\f[R] .IP \[bu] 2 \f[CB][{a: 1}] | path(foreach (0, \[dq]a\[dq]) as $i (\&.; \&.[$i])) \-\-> [0] [0, \[dq]a\[dq]]\f[R] .RE .PP به طور مشابه، می‌توانید از مسیرهای ترکیبی استفاده کنید: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | path(\&.[]?) \-\-> [0] [1] [2]\f[R] .IP \[bu] 2 \f[CB]\[dq]\[dq] | path(\&.[]?) \-\->\f[R] (بدون خروجی) .IP \[bu] 2 \f[CB]{a: [1, 2]} | path(\&.a[]) \-\-> [\[dq]a\[dq], 0] [\[dq]a\[dq], 1]\f[R] .RE .PP تمام فیلترهای دیگر تعریف‌شده در زبان هسته منجر به خطا می‌شوند، زیرا آن‌ها به جای برگرداندن ارجاع به ورودی‌هایشان، مقادیر جدیدی می‌سازند\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB]try path(0 ) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .IP \[bu] 2 \f[CB]try path(1 + 2) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .IP \[bu] 2 \f[CB]try path(1 = 2) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .RE .PP \f[I]سازگاری\f[R] .RS برنامه \f[CB]jq\f[R] از \f[CB]reduce\f[R] / \f[CB]foreach\f[R] در \f[CB]path\f[R] پشتیبانی نمی‌کند\&. .PP از سوی دیگر، \f[CB]jq\f[R] نسبت به مسیرهای مقادیر میانی آسان‌گیرتر است\&. برای نمونه، دستور \f[CB]try path([] | empty) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R]، زیرا jaq عبارت \f[CB]path([] | empty)\f[R] را به \f[CB]path([]) as $p | \&.\&.\&.\f[R] کاهش می‌دهد، که شکست می‌خورد زیرا \f[CB]path([])\f[R] تعریف نشده است\&. در مقابل، \f[CB]jq\f[R] برای این فیلتر هیچ خروجی‌ای نمی‌دهد\&. جالب اینجاست که \f[CB]path([] | \&.[])\f[R] در هر دو مفسر jaq و \f[CB]jq\f[R] خطا می‌دهد، بنابراین مشخص نیست چرا مثال با \f[CB]empty\f[R] خطا نمی‌دهد\&. .PP در jaq، عبارت \f[CB][] | path(\&.[0: ]) \-\-> [{\[dq]start\[dq]: 0}]\f[R] و \f[CB][] | path(\&.[ :0]) \-\-> [{\[dq]end\[dq] : 0}]\f[R] است، در حالی که \f[CB]jq\f[R] به ترتیب \f[CB][{start: 0 , end: null}]\f[R] و \f[CB][{start: null, end: 0 }]\f[R] را برمی‌گرداند\&. این بدان معنی است که \f[CB]jq\f[R] همواره ایندکس‌های ناموجود \f[CB]start\f[R]/\f[CB]end\f[R] را به عنوان \f[CB]null\f[R] اضافه می‌کند، در حالی که jaq آن‌ها را حذف می‌کند\&. .RE .SS "بدون مسیر (Pathless)" .PP مدل به‌روزرسانی بدون مسیر که توسط jaq استفاده می‌شود، به‌روزرسانی‌های \f[CB]p |= u\f[R] را بسته به \f[CB]p\f[R] به عبارات ساده‌تر تقلیل می‌دهد\&. این روش در رایج‌ترین موارد نتایج مشابهی با به‌روزرسانی‌های مبتنی بر مسیر تولید می‌کند، در حالی که مزایای زیر را دارد: .RS 2 .IP \[bu] 2 نیازی به ساخت مسیرها ندارد، که منجر به کارایی و عملکرد بالاتر می‌شود\&. .IP \[bu] 2 در صورت امکان، چندین خروجی توسط \f[CB]u\f[R] را در نظر می‌گیرد، در حالی که به‌روزرسانی‌های مبتنی بر مسیر حداکثر یک خروجی را لحاظ می‌کنند\&. برای نمونه: \f[CB]0 | (\&., \&.) |= (\&., \&.+1) \-\-> 0 1 1 2\f[R] در jaq، در حالی که در jq تنها مقدار \f[CB]0\f[R] را تولید می‌کند\&. با این حال، \f[CB]{a: 1} | \&.a |= (2, 3) \-\-> {\[dq]a\[dq]: 2}\f[R] در هر دو jaq و jq است، زیرا یک شیء تنها می‌تواند یک مقدار منفرد را با هر کلید معین مرتبط سازد، بنابراین ما نمی‌توانیم در اینجا از چند خروجی به شکل معناداری استفاده کنیم\&. .IP \[bu] 2 از مشکلات باطل شدن تکرارکننده (iterator invalidation) که به‌روزرسانی‌های مبتنی بر مسیر مستعد آن هستند، جلوگیری می‌کند\&. .RE .PP با این حال، به‌روزرسانی‌های بدون مسیر از چند فیلتر در سمت چپ به‌روزرسانی‌ها که مدل‌های مبتنی بر مسیر پشتیبانی می‌کنند، پشتیبانی نمی‌نمایند؛ مانند: .RS 2 .IP \[bu] 2 \f[CB]try f catch g\f[R] .IP \[bu] 2 \f[CB]first(f)\f[R]، \f[CB]last(f)\f[R] .IP \[bu] 2 \f[CB]limit($n; f)\f[R] .IP \[bu] 2 \f[CB]skip($n; f)\f[R] .RE .PP برای نمونه، فیلترهای زیر همگی در jaq منجر به خطا می‌شوند: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | try \&.[] \-= 1\f[R] در jq خروجی \f[CB][0, 1, 2]\f[R] می‌دهد\&. .IP \[bu] 2 \f[CB][1, 2, 3] | first( \&.[]) \-= 1\f[R] در jq خروجی \f[CB][0, 2, 3]\f[R] می‌دهد\&. .IP \[bu] 2 \f[CB][1, 2, 3] | limit(2; \&.[]) \-= 1\f[R] در jq خروجی \f[CB][0, 1, 3]\f[R] می‌دهد\&. .IP \[bu] 2 \f[CB][1, 2, 3] | skip (1; \&.[]) \-= 1\f[R] در jq خروجی \f[CB][1, 1, 2]\f[R] می‌دهد\&. .IP \[bu] 2 \f[CB][1, 2, 3] | last ( \&.[]) \-= 1\f[R] در jq خطا می‌دهد\&. .RE .PP در چنین مواردی، می‌توانید با نوشتن \f[CB]getpath(path(p)) |= u\f[R] به جای \f[CB]p |= u\f[R] در jaq به به‌روزرسانی‌های مبتنی بر مسیر بازگردید\&. برای نمونه، فیلترهای زیر خروجی‌های یکسانی در jaq و \f[CB]jq\f[R] تولید می‌کنند: .RS 2 .IP \[bu] 2 \f[CB][1, 2, 3] | getpath(path(try \&.[] )) \-= 1 \-\-> [0, 1, 2]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | getpath(path(first( \&.[]))) \-= 1 \-\-> [0, 2, 3]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | getpath(path(limit(2; \&.[]))) \-= 1 \-\-> [0, 1, 3]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | getpath(path(skip (1; \&.[]))) \-= 1 \-\-> [1, 1, 2]\f[R] .IP \[bu] 2 \f[CB][1, 2, 3] | getpath(path(last ( \&.[]))) \-= 1 \-\-> [1, 2, 2]\f[R] (این مثال در \f[CB]jq\f[R] خطا می‌دهد، در حالی که در jaq کار می‌کند) .RE .PP \f[I]سازگاری\f[R] .RS در \f[CB]jq\f[R]، دستور \f[CB]\&. |= empty\f[R] برای هر ورودی مقدار \f[CB]null\f[R] می‌دهد، در حالی که jaq هیچ خروجی‌ای نمی‌دهد\&. به طور مشابه، در \f[CB]jq\f[R]، دستور \f[CB]\&. |= (\&., \&.)\f[R] ورودی خود را یک بار بازمی‌گرداند، در حالی که jaq ورودی خود را دو بار برمی‌گرداند\&. .PP در \f[CB]jq\f[R]، دستور \f[CB][0, 1] | \&.[3] = 3\f[R] مقدار \f[CB][0, 1, null, 3]\f[R] را می‌دهد؛ یعنی \f[CB]jq\f[R] در صورتی که فراتر از اندازه لیست به‌روزرسانی کنیم، آن را با مقادیر \f[CB]null\f[R] پر می‌کند\&. در مقابل، jaq در چنین حالتی با خطای خارج از محدوده (out\-of\-bounds) مواجه می‌شود\&. .PP برنامه \f[CB]jq\f[R] از به‌روزرسانی برش‌های رشته پشتیبانی نمی‌کند، در حالی که jaq پشتیبانی می‌نماید\&. .PP در \f[CB]jq\f[R]، \f[CB]null | \&.a = 1\f[R] مقدار \f[CB]{\[dq]a\[dq]: 1}\f[R] و \f[CB]null | \&.[0] = 1\f[R] مقدار \f[CB][1]\f[R] را می‌دهد؛ بدین معنا که \f[CB]jq\f[R] هنگام به‌روزرسانی \f[CB]null\f[R] با یک ایندکس رشته‌ای یا عددی، با آن مانند آرایه یا شیء خالی رفتار می‌کند\&. از آنجا که jaq از کلیدهای شیء غیررشته‌ای پشتیبانی می‌کند، این کار دارای ابهام است، زیرا روشن نیست که آیا \f[CB]null | \&.[0] = 1\f[R] باید مقدار \f[CB]{0: 1}\f[R] یا \f[CB][1]\f[R] را تولید کند\&. به همین دلیل، jaq در به‌روزرسانی‌های null با هر نوع ایندکسی خطایی صادر می‌کند\&. .RE .SS "الگوها (PATTERNS)" .PP فیلتر \f[CB]f as $x | g\f[R] خروجی‌های \f[CB]f\f[R] را به یک متغیر \f[CB]$x\f[R] مقید می‌سازد\&. در جایگاه \f[CB]$x\f[R]، می‌توانیم از یک \f[B]الگو\f[R] (pattern) برای \f[I]تخریب / ساختارشکنی\f[R] (destructure) ورودی به چندین متغیر استفاده کنیم\&. .PP فیلتر زیر را در نظر بگیرید: .IP .EX [ 1, {a: 2}] | \&.[0] as $x | \&.[1]\&.a as $y | $x, $y \-\-> 1 2 .EE .PP می‌توانیم این را به شکل فشرده‌تر با استفاده از یک الگو چنین بنویسیم: .IP .EX [ 1, {a: 2}] as [$x, {a: $y}] | $x, $y \-\-> 1 2 .EE .PP در اینجا، \f[CB][$x, {a: $y}]\f[R] الگویی است که برای تطبیق با مقدار \f[CB][1, {a: 2}]\f[R] به کار می‌رود\&. این الگو \f[CB]1\f[R] را به \f[CB]$x\f[R] و \f[CB]2\f[R] را به \f[CB]$y\f[R] مقید می‌کند\&. .PP مشابه با ساخت شیء، \f[CB]{$x}\f[R] معادل با \f[CB]{x: $x}\f[R] برای الگوهای شیء نیز هست\&. برای نمونه، می‌توانستیم مثال قبل را به شکل معادل چنین بنویسیم: \f[CB][1, {a: 2}] as [$x, {$a}] | $x, $a \-\-> 1 2\f[R] .PP هنگامی که یک الگو در ورودی خود وجود نداشته باشد، متغیرهای متناظر آن به \f[CB]null\f[R] مقید می‌شوند: .RS 2 .IP \[bu] 2 \f[CB][1, {b: 2}] as [$x, {$a}] | $x, $a \-\-> 1 null\f[R] .IP \[bu] 2 \f[CB][1 ] as [$x, $y] | $x, $y \-\-> 1 null\f[R] .IP \[bu] 2 \f[CB][1, {a: 2}] as [$x, [$y]] | $x, $y \-\-> 1 null\f[R] .RE .PP اگر نوع‌های الگو و ورودی آن با هم مطابقت نداشته باشند، خطایی رخ می‌دهد: .RS 2 .IP \[bu] 2 \f[CB]try ([1] as {$a} | $a) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .IP \[bu] 2 \f[CB]try ( 1 as [$x] | $x) catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .RE .PP الگوها مجبور نیستند با تمام ورودی خود مطابقت داشته باشند: .RS 2 .IP \[bu] 2 \f[CB][ 1, 2] as [$x] | $x \-\-> 1\f[R] .IP \[bu] 2 \f[CB]{a: 1, b: 2} as {$a} | $a \-\-> 1\f[R] .RE .PP الگوها می‌توانند به طور دلخواه تو در تو باشند: .RS 2 .IP \[bu] 2 \f[CB]{a: [1, {b: [2]}]} as {a: [$x, {b: [$y]}]} | $x, $y \-\-> 1 2\f[R] .IP \[bu] 2 \f[CB][[[1]]] as [[[$x]]] | $x \-\-> 1\f[R] .IP \[bu] 2 \f[CB]{a: {b: {c: 1}}} as {a: {b: {c: $x}}} | $x \-\-> 1\f[R] .RE .PP می‌توانیم هر فیلتر \f[CB](f)\f[R] را به عنوان کلید شیء در یک الگو بنویسیم: .IP .EX {a: 1, b: 2, c: 3, d: 4} as {(\[dq]a\[dq], \[dq]b\[dq]): $x, (\[dq]c\[dq], \[dq]d\[dq]): $y} | [$x, $y] \-\-> [1, 3] [1, 4] [2, 3] [2, 4] .EE .PP همچنین می‌توانیم از الگوها در \f[CB]reduce\f[R] و \f[CB]foreach\f[R] استفاده کنیم: .IP .EX [{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}, {\[dq]a\[dq]: 3, \[dq]b\[dq]: 4}] | foreach \&.[] as {(\[dq]a\[dq], \[dq]b\[dq]): $x} ([]; \&. + [$x]) \-\-> [1] [1,2] [1,2,3] [1,2,3,4] .EE .PP \f[I]سازگاری\f[R] .RS دستور jaq از عملگر جایگزین ساختارشکنی \f[CB]jq\f[R] \c .UR https://jqlang.org/manual/#destructuring-alternative-operator \f[CB]?//\f[R] .UE \c پشتیبانی نمی‌کند\&. .RE .SS "ماژول‌ها (MODULES)" .PP دستور jq امکان تقسیم برنامه‌ها به چندین فایل را فراهم می‌کند که به آن‌ها \f[B]ماژول\f[R] گفته می‌شود\&. .PP در ابتدای هر ماژول jq، یک هدر ماژول قرار دارد که از یک توالی (احتمالاً خالی) از دستورالعمل‌های فهرست‌شده در این بخش تشکیل شده است\&. هدر ماژول سپس توسط توالی‌ای از تعاریف دنبال می‌شود\&. در نهایت، ماژول اصلی که از رابط خط فرمان فراخوانی می‌شود (از طریق \f[CB]\-\-from\-file\f[R] یا به صورت درون‌خطی) باید حاوی یک فیلتر واحد در انتها باشد، که همان فیلتری است که اجرا می‌شود\&. .PP تمامی دستورالعمل‌های \f[CB]include\f[R]/\f[CB]import\f[R] فایل‌ها را همان‌طور که در بخش مسیرهای جستجو توضیح داده شده است جستجو می‌کنند\&. .SS "متادیتای ماژول (Module metadata)" .PP دستورالعمل \f[CB]module meta;\f[R] متادیتای ماژول جاری را روی خروجی \f[CB]meta\f[R] تنظیم می‌کند، که در آن \f[CB]meta\f[R] یک فیلتر است\&. این دستورالعمل ممکن است تنها در ابتدای هدر ماژول و تنها یک بار رخ دهد\&. .PP برای نمونه: \f[CB]module \[dq]My module\[dq]; 1 \-\-> 1\f[R]\&. .PP \f[I]سازگاری\f[R] .RS دستور jaq این دستورالعمل را نادیده می‌گیرد، در حالی که \f[CB]jq\f[R] از آن برای ارائه خروجی \f[CB]meta\f[R] از طریق فیلتر \f[CB]modulemeta\f[R] استفاده می‌کند\&. .RE .SS "گنجاندن ماژول (Module inclusion)" .PP دستورالعمل‌های \f[CB]include \[dq]mod\[dq];\f[R] و \f[CB]include \[dq]mod\[dq] meta;\f[R] تمام فیلترهای تعریف‌شده در ماژول \f[CB]mod\&.jq\f[R] را در ماژول جاری در دسترس قرار می‌دهند\&. .PP برای نمونه، اگر \f[CB]foo\&.jq\f[R] در پوشه کاری جاری حاوی \f[CB]def bar: 1;\f[R] باشد، دستور \f[CB]jaq \-L \&. \-n \[aq]include \[dq]foo\[dq]; bar\[aq]\f[R] مقدار \f[CB]1\f[R] را بازمی‌گرداند\&. .SS "وارد کردن ماژول (Module import)" .PP دستورالعمل‌های \f[CB]import \[dq]mod\[dq] as name;\f[R] و \f[CB]import \[dq]mod\[dq] as name meta;\f[R] تمام تعاریف ماژول \f[CB]mod\&.jq\f[R] را در ماژول جاری با پیشوند \f[CB]name::\f[R] در دسترس قرار می‌دهند\&. .PP برای نمونه: .IP .EX $ echo \[aq]def bar: 1;\[aq] > foo\&.jq && jaq \-L \&. \-n \[aq]import \[dq]foo\[dq] as myfoo; myfoo::bar\[aq] && rm foo\&.jq 1 .EE .SS "وارد کردن داده (Data import)" .PP دستورالعمل‌های \f[CB]import \[dq]data\[dq] as $name;\f[R] و \f[CB]import \[dq]data\[dq] as $name meta;\f[R] تمام مقادیر JSON در \f[CB]data\&.json\f[R] را درون یک آرایه بارگذاری کرده، آن را به متغیر \f[CB]$name\f[R] مقید می‌کنند، و در ماژول جاری در دسترس قرار می‌دهند\&. .PP برای نمونه: .IP .EX $ echo 1 2 3 > foo\&.json && jaq \-L \&. \-nc \[aq]import \[dq]foo\&.json\[dq] as $myfoo; $myfoo\[aq] && rm foo\&.json [1,2,3] .EE .SS "مسیرهای جستجو (Search paths)" .PP دستورالعمل \f[CB]include\f[R]/\f[CB]import\f[R] فایل مورد نظر خود را در دایرکتوری‌های زیر و با ترتیب زیر جستجو می‌کند: .RS 2 .IP \[bu] 2 مسیرهای جستجوی سراسری مشخص‌شده از طریق \f[CB]\-\-library\-path\f[R]\&. آن‌ها به صورت نسبی نسبت به پوشه کاری جاری تفسیر می‌شوند\&. .IP \[bu] 2 مسیرهای جستجوی محلی مشخص‌شده از طریق متادیتا: هنگامی که یک دستورالعمل \f[CB]include\f[R]/\f[CB]import\f[R] دارای \f[CB]meta\f[R] به شکل \f[CB]{\&.\&.\&., search: \&.\&.\&., \&.\&.\&.}\f[R] باشد، مقدار موجود در کلید \f[CB]\[dq]search\[dq]\f[R] مسیرهای جستجوی محلی را برای آن دستورالعمل به صورت زیر تعیین می‌کند: .RS 2 .IP \[bu] 2 اگر مقدار یک رشته باشد: فقط همان رشته\&. .IP \[bu] 2 اگر مقدار یک آرایه باشد: تمام رشته‌های موجود در آرایه\&. .IP \[bu] 2 در غیر این صورت: هیچ‌چیز\&. .RE اگر ماژول حاوی دستورالعمل \f[CB]include\f[R]/\f[CB]import\f[R] یک فایل باشد، این مسیرها به صورت نسبی نسبت به دایرکتوری والد آن ماژول تفسیر می‌شوند\&. در غیر این صورت، این مسیرها به صورت نسبی نسبت به پوشه کاری جاری تفسیر می‌شوند\&. (این حالت زمانی است که ماژول حاوی دستورالعمل \f[CB]include\f[R]/\f[CB]import\f[R] به صورت درون‌خطی در خط فرمان داده شده باشد\&.) .RE .PP هر مسیر جستجوی سراسری و محلی به صورت زیر جایگزین می‌شود: .RS 2 .IP \[bu] 2 اگر با \f[CB]~\f[R] آغاز شود، \f[CB]~\f[R] با دایرکتوری خانگی کاربر که توسط متغیر محیطی \f[CB]HOME\f[R] در لینوکس و \f[CB]USERPROFILE\f[R] در ویندوز مشخص می‌شود جایگزین می‌گردد\&. .IP \[bu] 2 اگر با \f[CB]$ORIGIN\f[R] آغاز شود، \f[CB]$ORIGIN\f[R] با پوشه‌ای که فایل اجرایی \f[CB]jaq\f[R] در آن قرار دارد جایگزین می‌شود\&. .RE .PP برای نمونه: \f[CB]jaq \-L ~/foo \-L bar \[aq]include \[dq]decode\[dq] {search: [\[dq]baz\[dq], \[dq]$ORIGIN/quux\[dq]]}; 1\[aq]\f[R] فایل \f[CB]decode\&.jq\f[R] را در مسیرهای زیر و با ترتیب داده‌شده جستجو می‌کند: .RS 2 .IP \[bu] 2 \f[CB]~/foo/decode\&.jq\f[R] (که در آن \f[CB]~\f[R] با دایرکتوری خانگی کاربر جایگزین می‌شود) .IP \[bu] 2 \f[CB]\&./bar/decode\&.jq\f[R] .IP \[bu] 2 \f[CB]\&./baz/decode\&.jq\f[R] .IP \[bu] 2 \f[CB]$ORIGIN/quux/decode\&.jq\f[R] (که در آن \f[CB]$ORIGIN\f[R] با دایرکتوری والد فایل اجرایی \f[CB]jaq\f[R] جایگزین می‌شود) .RE .PP نخستین مسیری که با یک فایل موجود مطابقت داشته باشد برگزیده می‌شود\&. .PP حال فرض کنید که \f[CB]decode\&.jq\f[R] حاوی دستورالعمل \f[CB]import \[dq]binary\[dq] as $binary {search: \[dq]\&.\[dq]}\f[R] باشد\&. این دستور \f[CB]binary\&.json\f[R] را در مسیرهای زیر جستجو می‌کند: .RS 2 .IP \[bu] 2 \f[CB]~/foo/binary\&.json\f[R] .IP \[bu] 2 \f[CB]\&./bar/binary\&.json\f[R] (نسبت به پوشه کاری جاری) .IP \[bu] 2 \f[CB]\&./binary\&.json\f[R] (نسبت به پوشه والد \f[CB]decode\&.jq\f[R]) .RE .PP \f[I]سازگاری\f[R] .RS اگر فایلی برای بارگذاری بدون پسوند مشخص شده باشد، مانند \f[CB]decode\f[R] و \f[CB]binary\f[R] در بالا، دستور jaq پسوند را اضافه می‌کند (\f[CB]\&.jq\f[R] برای ماژول‌ها یا \f[CB]\&.json\f[R] برای داده‌ها)\&. برنامه \f[CB]jq\f[R] پسوند را \f[I]بدون قید و شرط\f[R] اضافه می‌کند؛ یعنی حتی اگر پسوندی به عنوان بخشی از نام فایل داده شده باشد، \f[CB]jq\f[R] مجدداً پسوند را اضافه می‌کند\&. .PP انگیزه رفتار jaq امکان‌پذیر ساختن دستورالعمل‌هایی مانند \f[CB]import \[dq]binary\&.cbor\[dq] as $binary\f[R] در آینده است\&. در اینجا، اضافه کردن بی‌قید و شرط پسوند \f[CB]\&.json\f[R] نتیجه عکس خواهد داشت\&. .RE .SS "توضیحات / کامنت‌ها (COMMENTS)" .PP یک توضیح (comment) با \f[CB]#\f[R] آغاز می‌شود و با نخستین خط جدیدی که قبل از آن تعداد فرد بک‌اسلش (\f[CB]\[rs]\f[R]) نیامده باشد پایان می‌یابد\&. برای نمونه: .IP .EX [ 1, # comment 2, # comment \[rs]\[rs] 3, # comment \[rs] comment 4, # comment \[rs]\[rs]\[rs] comment \[rs] comment 5 ] .EE .PP این معادل با \f[CB][1, 2, 3, 4, 5]\f[R] است\&. .SH "قالب‌ها (FORMATS)" .PP دستور jaq از خواندن و نوشتن چندین قالب داده پشتیبانی می‌کند\&. این بخش به شرح این قالب‌های داده می‌پردازد\&. .PP شما می‌توانید داده‌ها را در این قالب‌ها با استفاده از یکی از دو روش زیر بارگذاری کرده و بنویسید: .RS 2 .IP \[bu] 2 گزینه‌های خط فرمان \f[CB]\-\-from\f[R] / \f[CB]\-\-to\f[R]، یا .IP \[bu] 2 فیلترهای سریال‌سازی و واسریال‌سازی مانند \f[CB]fromjson\f[R] و \f[CB]toyaml\f[R] .RE .PP گزینه‌های خط فرمان \f[CB]\-\-from\f[R] و \f[CB]\-\-to\f[R] همواره عملکرد و کارایی بهتر یا برابری نسبت به فیلترهای متناظر ارائه می‌دهند\&. .SS JSON .PP \c .UR https://www.json.org JSON .UE \c (نشانه‌گذاری شیء جاوااسکریپت) در \c .UR https://datatracker.ietf.org/doc/html/rfc8259 RFC 8259 .UE \c مشخص شده است\&. .PP دستور jaq می‌تواند تمام مقادیر معتبر JSON را بخواند؛ با این حال، همانند \f[CB]jq\f[R]، مقادیر خاصی را که JSON نامعتبر هستند نیز می‌پذیرد\&. این مجموعه از مقادیر در بخش XJON مستند شده است\&. .SS XJON .PP قالب داده بومی jaq یک ابرمجموعه از JSON است که \f[B]XJON\f[R] نامیده می‌شود (eXtended JavaScript Object Notation، تلفظ مشابه “اکشن”)\&. .PP قالب XJON استاندارد JSON را با ساختارهای زیر گسترش می‌دهد: .RS 2 .IP \[bu] 2 کامنت‌های خطی: \f[CB]# \&.\&.\&. \[rs]n\f[R] به عنوان کامنت تفسیر می‌شود .IP \[bu] 2 اعداد ممیز شناور خاص: \f[CB]NaN\f[R]، \f[CB]Infinity\f[R]، \f[CB]+Infinity\f[R]، \f[CB]\-Infinity\f[R] .IP \[bu] 2 اعدادی که با \f[CB]+\f[R] یا چند صفر شروع می‌شوند: ابتدای یک عدد در XJON با عبارت منظم \f[CB][+\-]?\[rs]d+\f[R] و در JSON با \f[CB]\-?(0|[1\-9]\[rs]d*)\f[R] مطابقت دارد\&. بدین معنا که در XJON، \f[CB]+7\&.1\f[R]، \f[CB]007\f[R]، \f[CB]\-042\f[R] همگی اعدادی معتبر هستند، در حالی که در JSON نامعتبرند\&. .IP \[bu] 2 رشته‌های UTF\-8 با واحدهای کد نامعتبر: استاندارد JSON تا حدی مبهم است که آیا رشته‌ها ممکن است حاوی واحدهای کد نامعتبر UTF\-8 باشند یا خیر\&. قالب XJON صراحتاً واحدهای کد نامعتبر را در رشته‌های UTF\-8 مجاز می‌داند، برای نمونه خروجی \f[CB]printf \[aq]\[dq]\[rs]xFF\[dq]\[aq]\f[R]\&. این امر سازگاری با ابزارهایی را که چنین رشته‌هایی تولید می‌کنند (مانند نام فایل‌ها) افزایش می‌دهد\&. افزون بر این، امکان بارگذاری رشته‌ها در زمان ثابت را از طریق \f[CB]\-\-rawfile\f[R] فراهم می‌کند، جایی که jq به دلیل اعتبارسنجی UTF\-8 زمان خطی مصرف می‌کند\&. .IP \[bu] 2 رشته‌های بایتی: یک رشته بایتی از طریق \f[CB]b\[dq]\&.\&.\&.\[dq]\f[R] ساخته می‌شود، که در آن \f[CB]\&.\&.\&.\f[R] توالی‌ای از موارد زیر است: .RS 2 .IP \[bu] 2 بایت‌هایی در محدوده 0x20 تا (شامل) 0xFF، به استثنای نویسه‌های اسکی \f[CB]\[aq]\[dq]\[aq]\f[R] و \f[CB]\[aq]\[rs]\[aq]\f[R] .IP \[bu] 2 یک توالی گریز که با یک بک‌اسلش (\f[CB]\[aq]\[rs]\[aq]\f[R]) شروع شده و پس از آن \f[CB]b\f[R]، \f[CB]f\f[R]، \f[CB]n\f[R]، \f[CB]r\f[R]، \f[CB]t\f[R]، \f[CB]\[aq]\[dq]\[aq]\f[R]، \f[CB]\[aq]\[rs]\[aq]\f[R]، یا \f[CB]xHH\f[R] می‌آید که در آن \f[CB]HH\f[R] یک عدد هگزادسیمال است\&. برای نمونه: \f[CB]b\[dq]Here comes \[rs]xFF, dadadada\[rs]nHere comes \[rs]xFF\[rs]nAnd I say: \[rs]\[dq]It\[aq]s alright\[rs]\[dq]\[rs]x00\[dq]\f[R]\&. رشته‌های بایتی با این ساختار در زبان‌های دیگر نیز یافت می‌شوند؛ مانند راست و پایتون (با پیشوند \f[CB]b\f[R]) و جاوااسکریپت و C (بدون پیشوند \f[CB]b\f[R])\&. .RE .IP \[bu] 2 اشیاء با کلیدهای غیررشته‌ای: در حالی که JSON کلیدهای اشیاء را به رشته محدود می‌کند، قالب XJON مقادیر دلخواه را به عنوان کلید شیء می‌پذیرد\&. برای نمونه: \f[CB]{null: 0, true: 1, 2: 3, \[dq]str\[dq]: 4, [\[dq]arr\[dq]]: 5, {}: 6}\f[R] .RE .PP هدف از طراحی XJON پشتیبانی از مجموعه‌ای از مقادیر موجود در YAML و CBOR بود؛ یعنی رشته‌های بایتی و اشیاء دارای کلیدهای غیررشته‌ای، ضمن حفظ خوانایی انسانی قالب و سادگی و سرعت بالای تجزیه، همانند JSON\&. .PP قالب XJON می‌تواند هر مقدار jaq را بدون افت دقت کدگذاری کند؛ به ویژه اینکه رمزگشایی یک مقدار کدگذاری‌شده با XJON معادل با مقدار اولیه است\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB]nan | \&. | isnan \-\-> true\f[R] در jaq و \f[CB]jq\f[R] .IP \[bu] 2 \f[CB]nan | tojson | fromjson | isnan \-\-> true\f[R] در jaq، اما \f[CB]false\f[R] در \f[CB]jq\f[R] .RE .PP این بدان معناست که \f[CB]tojson | fromjson\f[R] در jaq معادل با \f[CB]\&.\f[R] است، در حالی که در \f[CB]jq\f[R] معادل \\f[I]نیست\\f[R]، به ویژه به دلیل مقادیر \f[CB]NaN\f[R] و \f[CB]Infinity\f[R]\&. .PP در حال حاضر هر جا که jaq مقدار JSON می‌پذیرد، XJON را نیز می‌پذیرد\&. این بدان معنی است که jaq مقادیر زیر را می‌پذیرد، حتی اگر JSON معتبر نباشند: .IP .EX $ echo \[aq]NaN b\[dq]Bytes\[dq] {1: 2} # Over and out\[aq] | jaq \-\-from json \-c NaN b\[dq]Bytes\[dq] {1:2} .EE .SS YAML .PP \c .UR https://yaml.org YAML .UE \c (YAML Ain’t Markup Language™) «یک زبان سریال‌سازی داده انسان‌پسند برای تمامی زبان‌های برنامه‌نویسی» است\&. این قالب همچنین یک ابرمجموعه از JSON و XJON محسوب می‌شود\&. بدین معنا که هر مقدار jaq می‌تواند به عنوان یک مقدار YAML کدگذاری شود\&. .PP دستور jaq از خواندن YAML با انکرها / لنگرها (\f[CB]&foo\f[R]) و نام‌های مستعار (\f[CB]*foo\f[R]) پشتیبانی می‌کند\&. این موارد امکان ایجاد ساختارهای داده به اشتراک گذاشته شده را فراهم می‌سازند\&. با این حال، jaq از داده‌های خودارجاع پشتیبانی نمی‌کند؛ یعنی داده‌هایی که حاوی یک نام مستعار اشاره‌کننده به خودشان باشند\&. برای نمونه: .RS 2 .IP \[bu] 2 \f[CB]\[dq][&a 1, &b 2, *a, *b]\[dq] | fromyaml \-\-> [1, 2, 1, 2]\f[R] .IP \[bu] 2 \f[CB]\[dq][&b [&a [], *a], *b]\[dq] | fromyaml \-\-> [[[], []], [[], []]]\f[R] .IP \[bu] 2 \f[CB]\[dq]&a[*a]\[dq] | try fromyaml catch \-1 \-\-> \-1\f[R] .RE .PP دستور jaq تگ‌ها را برای مقادیر اسکالر YAML مانند \f[CB]null\f[R]، بولی‌ها، اعداد و رشته‌ها اعتبارسنجی می‌کند: .RS 2 .IP \[bu] 2 \f[CB]\[dq]!!bool true\[dq] | fromyaml \-\-> true\f[R] .IP \[bu] 2 \f[CB]\[dq]!!int true\[dq] | try fromyaml catch \[dq]fail\[dq] \-\-> \[dq]fail\[dq]\f[R] .RE .PP از سوی دیگر، jaq تگ‌های مربوط به آرایه‌ها و اشیاء را نادیده می‌گیرد: .RS 2 .IP \[bu] 2 \f[CB]\[dq]!!foo []\[dq] | fromyaml \-\-> []\f[R] .IP \[bu] 2 \f[CB]\[dq]!!bar {}\[dq] | fromyaml \-\-> {}\f[R] .RE .PP دستور jaq خروجی YAML بسیار نزدیکی به JSON/XJON تولید می‌کند\&. خروجی فشرده YAML در jaq عمدتاً از این نظر با XJON تفاوت دارد که رشته‌های بایتی را به صورت رشته Base64 با تگ \f[CB]!!binary\f[R] و مقادیر ممیز شناور خاص را به صورت \f[CB]\&.inf\f[R]، \f[CB]\-\&.inf\f[R] و \f[CB]\&.nan\f[R] می‌نویسد: .IP .EX [infinite, \-infinite, nan, (\[dq]a\[dq] | tobytes), {\[dq]a\[dq]: 1}] | tojson, toyaml \-\-> \[dq][Infinity,\-Infinity,NaN,b\[rs]\[dq]a\[rs]\[dq],{\[rs]\[dq]a\[rs]\[dq]:1}]\[dq] \[dq][\&.inf, \-\&.inf, \&.nan, !!binary YQ==, {a: 1}]\[dq] .EE .PP دستور jaq توالی‌های نامعتبر UTF\-8 را در رشته‌های متنی هنگام نوشتن YAML حفظ می‌کند\&. با این حال، هنگام تلاش برای تجزیه YAML حاوی توالی‌های نامعتبر UTF\-8 خطا صادر می‌کند\&. .PP هنگام استفاده از \f[CB]\-\-to yaml\f[R]، دستور jaq علامت \f[CB]\-\-\-\f[R] را قبل از هر مقدار خروجی و علامت \f[CB]\&.\&.\&.\f[R] را بعد از هر مقدار خروجی می‌نویسد\&. این کار برای مشخص کردن شروع و پایان اسناد YAML انجام می‌شود\&. برای نمونه: .IP .EX $ jaq \-n \[aq][1, {a: 2, b: [3]}]\[aq] \-\-to yaml \-\-\- \- 1 \- a: 2 b: \- 3 \&.\&.\&. $ echo 1 2 | jaq \-\-to yaml \-\-\- 1 \&.\&.\&. \-\-\- 2 \&.\&.\&. .EE .PP از گزینه \f[CB]\-j\f[R] برای حذف نشانگرهای شروع/پایان سند YAML استفاده کنید\&. این گزینه می‌تواند هنگام ادغام چند آرایه مفید باشد: .IP .EX $ echo \[aq][1, 2] [3, 4]\[aq] | jaq \-\-to yaml \-j \- 1 \- 2 \- 3 \- 4 .EE .PP هر دو گزینه \f[CB]\-\-from yaml\f[R] و فیلتر \f[CB]fromyaml\f[R] کل ورودی را پیش از تجزیه در حافظه بارگذاری می‌کنند\&. .SS CBOR .PP \c .UR https://cbor.io CBOR .UE \c (Concise Binary Object Representation) یک قالب باینری است که در \c .UR https://www.rfc-editor.org/rfc/rfc8949.html RFC 8949 .UE \c مشخص شده است\&. .PP مقادیر CBOR یک ابرمجموعه از مقادیر jaq هستند\&. این بدان معناست که مقادیر خاصی در CBOR وجود دارند که هیچ مقدار معادلی در jaq برای آن‌ها وجود ندارد؛ برای نمونه: .RS 2 .IP \[bu] 2 \c .UR https://www.rfc-editor.org/rfc/rfc8949.html#name-epoch-based-date-time تاریخ\-زمان (date\-time) .UE \c .IP \[bu] 2 \c .UR https://www.rfc-editor.org/rfc/rfc8949.html#name-undefined-values تعریف‌نشده (undefined) .UE \c .IP \[bu] 2 \c .UR https://www.rfc-editor.org/rfc/rfc8949.html#fractions کسرهای ده‌دهی و ممیز شناورهای بزرگ (bigfloats) .UE \c .RE .PP دستور jaq هنگام تلاش برای رمزگشایی چنین مقادیر CBOR با شکست مواجه می‌شود\&. .PP هر مقدار jaq می‌تواند بدون افت دقت به عنوان مقدار CBOR کدگذاری شود، به جز رشته‌های متنی حاوی واحدهای کد نامعتبر UTF\-8\&. توالی‌های نامعتبر UTF\-8 با \f[CB]U+FFFD\f[R] که شبیه این است: “” جایگزین می‌شوند\&. .PP دستور jaq توالی‌های مقادیر CBOR را با الحاق بدون هیچ جداکننده‌ای می‌نویسد\&. این بدان معناست که \f[CB]\-\-to cbor\f[R] معادل با \f[CB]\-\-to cbor \-\-join\-output\f[R] است\&. دستور jaq همچنین می‌تواند توالی‌های مقادیر متصل CBOR را بخواند\&. .SS TOML .PP \c .UR https://toml.io TOML .UE \c یک قالب فایل پیکربندی است\&. می‌توانیم فایل‌های TOML را مانند فایل‌های JSON بخوانیم و جستجو کنیم: .IP .EX $ jaq \[aq]\&.profile\&.release[\[dq]codegen\-units\[dq]]\[aq] Cargo\&.toml 1 .EE .PP افزون بر این، می‌توانیم فایل‌های TOML نیز بنویسیم: .IP .EX $ echo \[aq]a = {b = 1, c = {d = nan, e = [], f = [{g = inf}, {h = \-inf}]}}\[aq] | jaq \-\-from toml \-\-to toml [a] b = 1 [a\&.c] d = nan e = [] [[a\&.c\&.f]] g = inf [[a\&.c\&.f]] h = \-inf .EE .PP در مقایسه با مقادیر jaq، قالب TOML مقادیر تاریخ\-زمان دارد، اما TOML هیچ‌یک از مقادیر \f[CB]null\f[R]، رشته‌های بایتی، یا کلیدهای غیررشته‌ای شیء را ندارد\&. علاوه بر این، ریشه مقدار TOML باید یک شیء باشد\&. این بدان معناست که نوشتن TOML ممکن است به روش‌های گوناگونی با شکست مواجه شود: .RS 2 .IP \[bu] 2 \f[CB]0 | try totoml catch \-1 \-\-> \-1\f[R] (ریشه غیرشیء) .IP \[bu] 2 \f[CB]{a: null } | try totoml catch \-1 \-\-> \-1\f[R] (مقدار null) .IP \[bu] 2 \f[CB]{a: 0 | tobytes} | try totoml catch \-1 \-\-> \-1\f[R] (رشته بایتی) .IP \[bu] 2 \f[CB]{(1): 2 } | try totoml catch \-1 \-\-> \-1\f[R] (کلید شیء غیررشته‌ای) .RE .PP دستور jaq می‌تواند مقادیر \c .UR https://toml.io/en/v1.1.0 TOML 1\&.1\&.0 .UE \c را بخواند، به استثنای مقادیر تاریخ\-زمان\&. دستور jaq به طور کلی باید بتواند مقادیر TOML را که خودش نوشته است دوباره بخواند، به استثنای اعداد صحیح بزرگ (big integers)\&. مثال زیر یک شیء \f[CB]{a: 2^1024}\f[R] حاوی یک عدد صحیح بزرگ می‌سازد، آن را با موفقیت به عنوان TOML می‌نویسد، و سپس هنگام خواندن مجدد آن شکست می‌خورد: .PP \f[CB]{a: nth(1024; 1 | recurse(\&.*2))} | totoml | try fromtoml catch \-1 \-\-> \-1\f[R] .PP هنگام نوشتن TOML، دستور jaq توالی‌های نامعتبر UTF\-8 را مشابه CBOR تبدیل می‌کند\&. این بدان معنی است که حتی اگر خواندن یک مقدار نوشته‌شده TOML با موفقیت همراه باشد، خروجی آن ممکن است با ورودی یکسان نباشد: .PP \f[CB]{a: [\-255] | implode} | (totoml | fromtoml) == \&. \-\-> false\f[R] .SS XML .PP دستور jaq داده‌های منطبق بر استاندارد \c .UR https://www.w3.org/TR/xml XML 1\&.0 .UE \c را می‌خواند\&. با این حال، تنها داده‌های XML کدگذاری‌شده به صورت UTF\-8 را پردازش می‌کند\&. .PP دستور jaq می‌تواند فایل‌های XHTML را بخواند، اما نمی‌تواند مستقیماً فایل‌های HTML را بخواند\&. می‌توانید از ابزارهایی مانند \c .UR https://github.com/jfisteus/html2xhtml html2xhtml .UE \c برای تبدیل HTML به XHTML استفاده کنید\&. .PP نگاشت‌های میان XML و JSON به طور کلی باید بین «کاربرپسند بودن» (friendliness) و رفت‌وبرگشت کامل (round\-tripping) مصالحه کنند؛ نگاه کنید به «\c .UR https://www.w3.org/2011/10/integration-workshop/p/XML_JSON_mapping_paper.pdf Experiences with JSON and XML Transformations .UE \c »\&. در اینجا، «کاربرپسند بودن» بدین معنی است که JSON تولیدشده از XML ساختاری مسطح دارد، که مصرف آن را آسان می‌کند\&. اشتفان گوسنر بحث بسیار خوبی درباره نگاشت‌های «کاربرپسند» گوناگون در مقاله «\c .UR https://www.xml.com/pub/a/2006/05/31/converting-between-xml-and-json.html Converting Between XML and JSON .UE \c » ارائه کرده است\&. پیام اصلی این است: نگاشت‌های «کاربرپسند» اطلاعات را از دست می‌دهند\&. به همین دلیل، jaq از نگاشت «کاربرپسند» استفاده نمی‌کند، بلکه از نگاشتی بهره می‌برد که اطلاعات XML را کاملاً حفظ می‌کند، و آن را برای رفت‌وبرگشت کامل (round\-tripping) مناسب می‌سازد\&. .PP به عنوان نمونه، ورودی زیر را در نظر بگیرید: .IP .EX <a href=\[dq]https://www\&.w3\&.org\[dq]>World Wide Web Consortium (<em>W3C</em>)</a> .EE .PP می‌توانیم نمایش داخلی آن را در jaq با دستور زیر ببینیم: .IP .EX $ echo \[aq]<a href=\[dq]https://www\&.w3\&.org\[dq]>World Wide Web Consortium (<em>W3C</em>)</a>\[aq] \[rs] | jaq \-\-from xml \&. { \[dq]t\[dq]: \[dq]a\[dq], \[dq]a\[dq]: { \[dq]href\[dq]: \[dq]https://www\&.w3\&.org\[dq] }, \[dq]c\[dq]: [ \[dq]World Wide Web Consortium (\[dq], { \[dq]t\[dq]: \[dq]em\[dq], \[dq]c\[dq]: [ \[dq]W3C\[dq] ] }, \[dq])\[dq] ] } .EE .SS "اشیاء TAC (TAC objects)" .PP تگ‌ها توسط \f[I]اشیاء TAC\f[R] نمایش داده می‌شوند\&. یک شیء TAC می‌تواند فیلدهای زیر را داشته باشد: .RS 2 .IP \[bu] 2 \f[CB]t\f[R]: نام تگ، مانند \f[CB]h1\f[R] برای \f[CB]<h1>\&.\&.\&.</h1>\f[R]\&. این فیلد همواره باید در یک شیء TAC وجود داشته باشد\&. .IP \[bu] 2 \f[CB]a\f[R]: مشخصه‌ها و صفات تگ، مانند \f[CB]{\[dq]id\[dq]: \[dq]foo\[dq], style: \[dq]color:blue;\[dq]}\f[R]\&. اگر این فیلد وجود داشته باشد، باید شامل شیئی با مقادیر رشته‌ای باشد\&. .IP \[bu] 2 \f[CB]c\f[R]: فرزندان تگ\&. اگر این فیلد وجود نداشته باشد، تگ به صورت خودبسته (self\-closing، مانند \f[CB]<br/>\f[R]) تفسیر می‌شود\&. هنگامی که یک شیء TAC تولیدشده توسط jaq (چه از طریق \f[CB]\-\-from xml\f[R] یا \f[CB]fromxml\f[R]) دارای فیلد \f[CB]c\f[R] باشد، همواره آرایه‌ای از مقادیر XML را نگه می‌دارد\&. هنگام نوشتن مقادیر XML (چه از طریق \f[CB]\-\-to xml\f[R] یا \f[CB]toxml\f[R])، دستور jaq هر مقدار XML را در فیلد \f[CB]c\f[R] می‌پذیرد\&. .RE .PP یک پرس‌وجوی نمونه برای به دست آوردن تمام پیوندها در یک فایل XHTML: .IP .EX \&.\&. | select(\&.t? == \[dq]a\[dq]) | \&.a\&.href .EE .PP ما همچنین می‌توانیم XML ورودی را تغییر شکل داده و XML خروجی تولید کنیم\&. برای نمونه، جهت تبدیل تمام تگ‌های \f[CB]em\f[R] به تگ‌های \f[CB]i\f[R]: .IP .EX (\&.\&. | select(\&.t? == \[dq]em\[dq]) | \&.t) = \[dq]i\[dq] .EE .PP برای تولید خروجی XML به جای خروجی JSON، از گزینه \f[CB]\-\-to xml\f[R] استفاده کنید: .IP .EX $ echo \[aq]<a href=\[dq]https://www\&.w3\&.org\[dq]>World Wide Web Consortium (<em>W3C</em>)</a>\[aq] \[rs] | jaq \-\-from xml \-\-to xml \[aq](\&.\&. | select(\&.t? == \[dq]em\[dq]) | \&.t) = \[dq]i\[dq]\[aq] <a href=\[dq]https://www\&.w3\&.org\[dq]>World Wide Web Consortium (<i>W3C</i>)</a> .EE .PP در نهایت، می‌توانیم تمام متن را از یک فایل XML استخراج کنیم (با صرف‌نظر از بلوک‌های CDATA): .IP .EX def xml_text: if isstring then \&. else \&.c[]? | xml_text end; [xml_text] .EE .SS "سایر مقادیر (Other values)" .RS 2 .IP \[bu] 2 رشته‌ها اسکیپ یا غیراسکیپ نمی‌شوند؛ بدین معنی که \f[CB]Tom & Jerry\f[R] در XML منبع تبدیل می‌شود به \f[CB]\[dq]Tom & Jerry\[dq]\f[R] در JSON مقصد\&. فیلترهای \f[CB]@html\f[R]/\f[CB]@htmld\f[R] می‌توانند برای اسکیپ کردن یا لغو اسکیپ دستی استفاده شوند\&. .IP \[bu] 2 یک کامنت مانند \f[CB]<!\-\- this comment \-\->\f[R] تبدیل می‌شود به \f[CB]{\[dq]comment\[dq]: \[dq] this comment \[dq]}\f[R]\&. .IP \[bu] 2 یک بلوک CDATA مانند \f[CB]<![CDATA[Tom & Jerry]]>\f[R] تبدیل می‌شود به \f[CB]{\[dq]cdata\[dq]: \[dq]Tom & Jerry\[dq]}\f[R]\&. .IP \[bu] 2 یک اعلان XML مانند \f[CB]<?xml version=\[dq]1\&.0\[dq] encoding=\[dq]UTF\-8\[dq] standalone=\[dq]yes\[dq]?>\f[R] تبدیل می‌شود به \f[CB]{\[dq]xmldecl\[dq]: {\[dq]version\[dq]: \[dq]1\&.0\[dq], \[dq]encoding\[dq]: \[dq]UTF\-8\[dq], \[dq]standalone\[dq]: \[dq]yes\[dq]}}\f[R]\&. (توجه داشته باشید که مقادیر داده‌شده در این اعلان، مانند کدگذاری، توسط تجزیه‌کننده XML در jaq نادیده گرفته می‌شوند\&.) .IP \[bu] 2 یک دستورالعمل پردازش (PI) مانند \f[CB]<?xml\-stylesheet href=\[dq]common\&.css\[dq]?>\f[R] تبدیل می‌شود به \f[CB]{\[dq]pi\[dq]: {\[dq]target\[dq]: \[dq]xml\-stylesheet\[dq], \[dq]content\[dq]: \[dq]href=\[rs]\[dq]common\&.css\[rs]\[dq]\[dq]}}\f[R]\&. .RE .PP برای کنار هم قرار دادن تمام این موارد، فایل XML زیر را در نظر بگیرید: .IP .EX $ cat examples/test\&.xhtml <?xml version=\[aq]1\&.0\[aq]?> <?xml\-stylesheet href=\[dq]common\&.css\[dq]?> <!DOCTYPE html> <html xmlns=\[dq]http://www\&.w3\&.org/1999/xhtml\[dq]> <body> <!\-\- CDATA blocks do not require escaping \-\-> <![CDATA[Hello & goodbye!]]><br/> </body> </html> .EE .PP این دستور در jaq خروجی زیر را می‌دهد: .IP .EX $ jaq \&. examples/test\&.xhtml { \[dq]xmldecl\[dq]: { \[dq]version\[dq]: \[dq]1\&.0\[dq] } } { \[dq]pi\[dq]: { \[dq]target\[dq]: \[dq]xml\-stylesheet\[dq], \[dq]content\[dq]: \[dq]href=\[rs]\[dq]common\&.css\[rs]\[dq]\[dq] } } { \[dq]doctype\[dq]: { \[dq]name\[dq]: \[dq]html\[dq] } } { \[dq]t\[dq]: \[dq]html\[dq], \[dq]a\[dq]: { \[dq]xmlns\[dq]: \[dq]http://www\&.w3\&.org/1999/xhtml\[dq] }, \[dq]c\[dq]: [ \[dq]\[rs]n \[dq], { \[dq]t\[dq]: \[dq]body\[dq], \[dq]c\[dq]: [ \[dq]\[rs]n \[dq], { \[dq]comment\[dq]: \[dq] CDATA blocks do not require escaping \[dq] }, \[dq]\[rs]n \[dq], { \[dq]cdata\[dq]: \[dq]Hello & goodbye!\[dq] }, { \[dq]t\[dq]: \[dq]br\[dq] }, \[dq]\[rs]n \[dq] ] }, \[dq]\[rs]n\[dq] ] } .EE .PP خروجی شامل مقادیر متعددی است که تنها از فاصله‌های خالی تشکیل شده‌اند، مانند \f[CB]\[dq]\[rs]n \[dq]\f[R]\&. این مقادیر توسط jaq حفظ می‌شوند زیرا XML قالبی حساس به فاصله‌های خالی است\&. .SS CSV / TSV .PP \c .UR https://www.rfc-editor.org/rfc/rfc4180 CSV .UE \c (مقادیر جداشده با کاما) و TSV (مقادیر جداشده با تب) قالب‌های داده جدولی هستند\&. یک جدول CSV/TSV از ردیف‌هایی از فیلدها تشکیل شده است\&. ردیف‌ها با خطوط جدید از هم جدا می‌شوند\&. فیلدها در CSV با کاما و در TSV با نویسه تب از هم تفکیک می‌گردند\&. .PP دستور jaq هر ردیف را به عنوان آرایه‌ای از مقادیر تفسیر می‌کند: .IP .EX $ printf \[dq]a,b\[rs]n1,2\[rs]n3,4\[dq] | jaq \-c \-\-from csv [\[dq]a\[dq],\[dq]b\[dq]] [1,2] [3,4] $ printf \[dq]a,b\[rs]n1,2\[rs]n3,4\[dq] | jaq \-c \-\-from csv \-\-slurp [[\[dq]a\[dq],\[dq]b\[dq]],[1,2],[3,4]] .EE .PP هنگام نوشتن جداول با استفاده از \f[CB]\-\-to\f[R]، دستور jaq خروجی خام فیلتر \f[CB]tocsv\f[R] / \f[CB]totsv\f[R] را چاپ می‌کند: .IP .EX $ jaq \-n \[aq][\[dq]a\[dq],\[dq]b\[dq]], [1,2], [3,4]\[aq] \-\-to csv \[dq]a\[dq],\[dq]b\[dq] 1,2 3,4 $ jaq \-n \[aq][\[dq]a\[dq],\[dq]b\[dq]], [1,2], [3,4] | @csv\[aq] \-\-raw\-output \[dq]a\[dq],\[dq]b\[dq] 1,2 3,4 .EE .SS "سرستون‌ها (Headers)" .PP دستور jaq در حال حاضر پردازش ویژه‌ای برای سرستون‌های جدول ارائه نمی‌دهد، که در آن ردیف نخست جدول حاوی نام فیلدها است\&. با این حال، چند فیلتر در \f[CB]examples/table\&.jq\f[R] وجود دارد که هدف آن‌ها ساده‌سازی مدیریت جداول دارای سرستون است\&. اگر این فیلترها را مفید یافتید یا مشکلی در آن‌ها دیدید، لطفاً \c .UR https://github.com/01mf02/jaq/issues/418 بازخورد خود را ارسال کنید .UE \c تا به من در تصمیم‌گیری برای ادغام آن‌ها در کتابخانه استاندارد jaq کمک کنید\&. بیایید نحوه استفاده از آن‌ها را ببینیم\&. .PP برای نمونه، بیایید به پرونده تحصیلی \c .UR https://en.wikipedia.org/wiki/Ferris_Bueller%27s_Day_Off فریس بیولر .UE \c نگاهی بیندازیم: .IP .EX $ cat examples/ferris\&.csv ID,Name,Home phone,Days absent 38\-106,\[dq]Bueller, Ferris\[dq],555\-6452,9 .EE .PP خواندن این فایل کمی دشوار است، و ادوارد آر\&. رونی، ناظم مدرسه، فردی پرمشغله است\&. بیایید کمی به او کمک کنیم: .IP .EX $ jaq \-L examples \[aq]include \[dq]table\[dq]; from_table\[aq] \-s examples/ferris\&.csv { \[dq]ID\[dq]: \[dq]38\-106\[dq], \[dq]Name\[dq]: \[dq]Bueller, Ferris\[dq], \[dq]Home phone\[dq]: \[dq]555\-6452\[dq], \[dq]Days absent\[dq]: 9 } .EE .PP بسیار بهتر شد\&. حالا ادوارد آر\&. رونی درباره فریس به مادر او چه می‌گوید؟ .RS .PP «تا اینجای ترم، اون نُه بار غیبت داشته\&.» — «نُه بار؟» — «نُه بار\&.» — «یادم نمیاد اون نُه بار مریض شده باشه\&.» — «احتمالاً به این خاطره که مریض نبوده؛ داشته مدرسه رو می‌پیچونده\&. چشماتون رو باز کنید خانم بیولر\&. سرتون کلاه گذاشته\&.» — «باورم نمیشه\&.» — «همینجا جلوم دارمش\&. اون نُه روز غیبت داشته\&.» .RE .PP حالا نوبت درخشش فریس است: .IP .EX $ jaq \-L examples \[aq]include \[dq]table\[dq]; from_table | \&.[\[dq]Days absent\[dq]] \-= 7\[aq] \-s examples/ferris\&.csv { \[dq]ID\[dq]: \[dq]38\-106\[dq], \[dq]Name\[dq]: \[dq]Bueller, Ferris\[dq], \[dq]Home phone\[dq]: \[dq]555\-6452\[dq], \[dq]Days absent\[dq]: 2 } .EE .RS .PP «گریس! گریسسسسس!!!» .RE .PP در ادامه، نگاهی به دروس فریس بیندازیم: .IP .EX $ cat examples/ferris\-courses\&.tsv Perds Days Course Teacher Rm Grade 1 Grade 2 Grade 3 Grade EX 01\-04 MTWF Eng Comp Hollndr 221 B+ A 05\-08 MWTF Calculus McMurry 309 B A\- 09\-10 TWTF Chemistry Gunner 260 A\- A 11\-13 All Lunch Caf 14\-19 MTWF Gym Carlyle 127 B+ A\- 23\-25 TWTF Computr Sc Cohen 114 A\- A 26\-29 MWTF Utpian Scy Jardin 241 A A 30\-32 MTWF Euro Hist Rice 334 B+ B+ .EE .PP بیایید ببینیم … فریس در کدام درس‌ها به عنوان نمره اول +B گرفته است؟ کسی نظری دارد؟ .IP .EX $ jaq \-L examples \[aq]include \[dq]table\[dq]; with_table(map(select(\&.[\[dq]Grade 1\[dq]] == \[dq]B+\[dq])))\[aq] \[rs] \-s examples/ferris\-courses\&.tsv \-\-to tsv Perds Days Course Teacher Rm Grade 1 Grade 2 Grade 3 Grade EX 01\-04 MTWF Eng Comp Hollndr 221 B+ A 14\-19 MTWF Gym Carlyle 127 B+ A\- 30\-32 MTWF Euro Hist Rice 334 B+ B+ .EE .PP بله، فریس … هنوز کمی کار روی پایگاه‌داده داری\&. .PP تا اینجا، ما تمام جداول را پیش از پردازش با استفاده از \f[CB]\-s\f[R] بارگذاری (slurp) کردیم\&. این کار می‌تواند به ویژه هنگام پردازش جداول بزرگ ناکارآمد باشد، زیرا کل جدول را درون حافظه می‌خواند\&. ما همچنین می‌توانیم جداول را ردیف‌به‌ردیف بخوانیم: یک الگوی مفید در اینجا استفاده از \f[CB]inputs\f[R] \f[B]بدون\f[R] گزینه معمول \f[CB]\-n\f[R] است\&. بدین ترتیب، ردیف اول (= سرستون) ورودی فیلتر می‌شود، و ردیف‌های باقی‌مانده می‌توانند با \f[CB]inputs\f[R] بازیابی شوند\&. با در کنار هم قرار دادن این‌ها، می‌توانیم مثال قبلی را بازنویسی کنیم: .IP .EX $ jaq \-L examples \[aq]include \[dq]table\[dq]; \&., \&. as $header | from_row(inputs) | select(\&.[\[dq]Grade 1\[dq]] == \[dq]B+\[dq]) | to_row($header)\[aq] \[rs] examples/ferris\-courses\&.tsv \-\-to tsv Perds Days Course Teacher Rm Grade 1 Grade 2 Grade 3 Grade EX 01\-04 MTWF Eng Comp Hollndr 221 B+ A 14\-19 MTWF Gym Carlyle 127 B+ A\- 30\-32 MTWF Euro Hist Rice 334 B+ B+ .EE .PP این بخش ماجرای فریس بیولر را به پایان می‌رساند\&. اگر هنوز این فیلم را ندیده‌اید، اکیداً پیشنهاد می‌کنم آن را تماشا کنید\&. و به یاد داشته باشید: «زندگی با سرعت زیادی می‌گذره\&. اگه گهگاهی نایستی و به اطرافت نگاه نکنی، ممکنه از دستش بدی\&.» .SH "مثال‌ها (EXAMPLES)" .PP مثال‌های زیر باید دیدی کلی از آنچه jaq در حال حاضر قادر به انجام آن است ارائه دهند\&. با جایگزین کردن jaq با jq باید دقیقاً همان خروجی‌ها را دریافت کنید\&. .PP دسترسی به یک فیلد: .IP .EX $ echo \[aq]{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\[aq] | jaq \[aq]\&.a\[aq] 1 .EE .PP جمع مقادیر: .IP .EX $ echo \[aq]{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\[aq] | jaq \[aq]add\[aq] 3 .EE .PP ساخت یک آرایه از یک شیء به دو روش و نشان دادن برابری آن‌ها: .IP .EX $ echo \[aq]{\[dq]a\[dq]: 1, \[dq]b\[dq]: 2}\[aq] | jaq \[aq][\&.a, \&.b] == [\&.[]]\[aq] true .EE .PP اعمال یک فیلتر روی تمام عناصر یک آرایه و فیلتر کردن نتایج: .IP .EX $ echo \[aq][0, 1, 2, 3]\[aq] | jaq \-c \[aq]map(\&.*2) | [\&.[] | select(\&. < 5)]\[aq] [0,2,4] .EE .PP خواندن (slurp) مقادیر ورودی درون یک آرایه و به دست آوردن میانگین عناصر آن: .IP .EX $ echo \[aq]1 2 3 4\[aq] | jaq \-s \[aq]add / length\[aq] 2\&.5 .EE .PP اعمال مکرر یک فیلتر روی خودش و خروجی دادن نتایج میانی: .IP .EX $ echo \[aq]0\[aq] | jaq \-c \[aq][recurse(\&.+1; \&. < 3)]\[aq] [0,1,2] .EE .PP تاکردن غیرحریصانه (lazy fold) روی ورودی‌ها و خروجی دادن نتایج میانی: .IP .EX $ seq 5 | jaq \-n \[aq]foreach inputs as $x (0; \&. + $x)\[aq] 1 3 6 10 15 .EE .SS "معمای لوئیس (LEWIS’S PUZZLE)" .PP معمای زیر در یک کارگاه آموزشی توسط فردی به نام آقای لوئیس با من مطرح شد، جایی که آن را همراه او در jq حل کردم\&. معما به شرح زیر است: .PP ما دنباله‌ای از رشته‌ها داریم: .IP .EX X XYZX XYZXABXYZX .EE .PP برای نمونه، چهارمین حرف از رشته دوم (همیشه با شروع شمارش از صفر) حرف ‘A’ است\&. حرف ۱۰۲۴۴ام از رشته سی‌ام چیست؟ .PP نخست، بیایید بفهمیم این دنباله چگونه ساخته می‌شود\&. برای به دست آوردن دنباله بعدی حروف، دنباله قبلی را برمی‌داریم، آن را با دو حرف بعدی الفبا الحاق می‌کنیم، و سپس دوباره با دنباله قبلی الحاق می‌نماییم\&. .PP اگر به جای حروف از اعداد استفاده کنیم، می‌توانیم آن را به این صورت بنویسیم: .IP .EX X(0 ) = 0 X(N+1) = X(N) (m+1) (m+2) X(N), where m is the largest element in X(N) .EE .PP اکنون می‌توانیم این رشته‌ها را به عنوان آرایه‌های JSON بنویسیم\&. آرایه اول \f[CB][0]\f[R] است، و می‌توانیم هر آرایه بعدی را با فیلتر \f[CB]next\f[R] بسازیم، که با \f[CB]recurse\f[R] روی آن دنباله‌ای از تمام آرایه‌ها را به دست می‌آوریم\&. .IP .EX def next: \&. + [max + (1, 2)] + \&.; [0] | limit(3; recurse(next)) \-\-> [0] [0,1,2,0] [0,1,2,0,3,4,0,1,2,0] .EE .PP با این حال، این روش مقیاس‌پذیر نیست — رسیدن به آرایه سی‌ام زمان بسیار زیادی خواهد برد، زیرا آرایه‌ها به صورت نمایی رشد می‌کنند\&. می‌توانید آن را امتحان کنید، اما مراقب باشید رم (RAM) سیستم تمام نشود\&. :) (توصیه می‌کنم هنگام انجام این آزمایش مصرف رم را زیر نظر داشته باشید؛ در غیر این صورت، ممکن است رایانه شما به دلیل اتمام حافظه به کلی متوقف شود\&. حدس بزنید از کجا می‌دانم؟) .PP برای حل این مشکل، می‌توانیم از اشتراک‌گذاری داده‌ها در jq بهره ببریم\&. توجه داشته باشید که هر آرایه شامل بخشی در سمت چپ است که برابر است با بخشی در سمت راست؛ برای نمونه، \f[CB][0, 1, 2, 0]\f[R] در آرایه دوم\&. بنابراین می‌توانیم نمایشی اندکی متفاوت از آرایه انتخاب کنیم که به ما امکان می‌دهد بخش‌های برابر آرایه را به سادگی با قرار دادن آرایه‌های قبلی درون یک آرایه جدید، به \\f[B]اشتراک\\f[R] بگذاریم\&. .IP .EX def next: [\&., \&.[2] + (1,2), \&.]; [0] | limit(3; recurse(next)) \-\-> [0] [[0],1,2,[0]] [[[0],1,2,[0]],3,4,[[0],1,2,[0]]] .EE .PP در تمامی آرایه‌های تولیدشده توسط \f[CB]next\f[R]، عناصر اول و آخر اکنون به اشتراک گذاشته شده‌اند، بدین معنی که فقط یک بار در حافظه ذخیره می‌شوند\&. این کار به ما امکان می‌دهد داده‌های با اندازه نمایی را در حافظه خطی ذخیره کنیم، و بدین ترتیب معما را حل کنیم\&. .PP برای به دست آوردن بزرگ‌ترین عدد آرایه قبلی، از این واقعیت استفاده کردیم که عنصر دوم هر آرایه حاوی بزرگ‌ترین عدد موجود در آرایه است\&. برای نمونه: عنصر دوم آرایه اول \f[CB]2\f[R] است، و عنصر دوم آرایه دوم \f[CB]4\f[R] است\&. (برای آرایه صفرم، عنصر دوم \f[CB]null\f[R] است، اما بیشینه عنصر آن آرایه \f[CB]0\f[R] است\&. با این حال، \f[CB]null\f[R] در عمل جمع دقیقاً مانند \f[CB]0\f[R] تفسیر می‌شود، بنابراین این تفاوت اهمیتی ندارد\&.) بنابراین می‌توانیم دو عدد بزرگ‌تر بعدی را به زیبایی از طریق \f[CB]\&.[2] + (1, 2)\f[R] به دست آوریم\&. .PP اکنون می‌توانیم اعداد هر چنین آرایه‌ای را با \f[CB]\&.\&. | numbers\f[R] دریافت کنیم\&. برای نمونه، اعداد آرایه دوم عبارتند از: .IP .EX [[[0],1,2,[0]],3,4,[[0],1,2,[0]]] | \&.\&. | numbers \-\-> 0 1 2 0 3 4 0 1 2 0 .EE .PP با کنار هم قرار دادن تمام این موارد، راه‌حل ما حاصل می‌شود: .IP .EX def next: [\&., \&.[2] + (1,2), \&.]; [0] | nth(30; recurse(next)) | nth(10244; \&.\&. | numbers) \-\-> 2 .EE .PP این دستور اکنون تقریباً آنی اجرا می‌شود و پاسخ \f[CB]2\f[R] را به ما می‌دهد\&. با بازگشت به معمای اصلی، از آنجا که \f[CB]X = 0\f[R]، \f[CB]Y = 1\f[R] و \f[CB]Z = 2\f[R] است، پاسخ نهایی معما حرف \f[CB]Z\f[R] است\&. .SS "استخراج از HTML (HTML SCRAPING)" .PP من می‌خواستم \c .UR https://www.rfc-editor.org/rfc/rfc8949.html#name-examples-of-encoded-cbor-da فهرست مثال‌ها را از مشخصات CBOR .UE \c استخراج کنم تا مجموعه آزمایشی برای رمزگذار/رمزگشای CBOR در jaq ایجاد کنم\&. برای این کار، بخش مربوطه را از کد منبع HTML کپی کرده و در فایل \f[CB]examples/cbor\-examples\&.xhtml\f[R] قرار دادم\&. بخش‌های جالب آن به این صورت است: .IP .EX <table> <tbody> <tr> <td class=\[dq]text\-left\[dq] rowspan=\[dq]1\[dq] colspan=\[dq]1\[dq]>25</td> <td class=\[dq]text\-left\[dq] rowspan=\[dq]1\[dq] colspan=\[dq]1\[dq]>0x1819</td> </tr> <tr> <td class=\[dq]text\-left\[dq] rowspan=\[dq]1\[dq] colspan=\[dq]1\[dq]>100</td> <td class=\[dq]text\-left\[dq] rowspan=\[dq]1\[dq] colspan=\[dq]1\[dq]>0x1864</td> </tr> </tbody> </table> .EE .PP در اینجا، من به جفت‌های \f[CB]25\f[R] / \f[CB]0x1819\f[R] و \f[CB]100\f[R] / \f[CB]0x1864\f[R] علاقه‌مند بودم؛ بدین معنی که عدد \f[CB]25\f[R] در CBOR به صورت \f[CB]0x1819\f[R] کدگذاری می‌شود\&. .PP در نهایت، من برنامه‌ای در jq برای استخراج این داده‌ها طراحی کردم\&. این برنامه از مراحل زیر تشکیل شده است: .RS 2 .IP \[bu] 2 انتخاب تمام عناصر \f[CB]<tr>\f[R] با \f[CB]\&.\&. | select(\&.t? == \[dq]tr\[dq])\f[R]\&. .IP \[bu] 2 دریافت فرزندان آن با \f[CB]\&.c\f[R]\&. .IP \[bu] 2 پیمایش روی فرزندان با \f[CB]\&.[]\f[R] و دریافت فرزندان آن‌ها با \f[CB]\&.c?[]\f[R]\&. .RE .PP (من در اینجا به جای \f[CB]\&.c\f[R] از \f[CB]\&.c?\f[R] استفاده می‌کنم چون XML به فاصله‌های خالی حساس است؛ بنابراین در \f[CB]<tr> <td></td> </tr>\f[R]، عنصر \f[CB]<tr>\f[R] در واقع سه فرزند دارد: دو رشته فاصله \f[CB]\[dq] \[dq]\f[R] و عنصر \f[CB]<td>\f[R]\&. ایندکس کردن رشته‌ها با \f[CB]\&.c\f[R] خطا می‌دهد، در حالی که ایندکس کردن آن‌ها با \f[CB]\&.c?\f[R] صرفاً هیچ چیزی برنمی‌گرداند و به ما امکان می‌دهد فاصله‌ها را نادیده بگیریم\&.) .PP می‌توانیم اثرات آن را روی نسخه‌ای ساده‌شده از HTML ببینیم: .IP .EX \[dq]<table>\[dq] + \[dq]<tr> <td>25</td> <td>0x1819</td> </tr>\[dq] + \[dq]<tr> <td>100</td> <td>0x1864</td> </tr>\[dq] + \[dq]</table>\[dq] | fromxml | \&.\&. | select(\&.t? == \[dq]tr\[dq])\&.c | [\&.[]\&.c?[]] \-\-> [ \[dq]25\[dq], \[dq]0x1819\[dq]] [\[dq]100\[dq], \[dq]0x1864\[dq]] .EE .PP برای اجرای این دستور از طریق خط فرمان (CLI): .IP .EX jaq \[aq]\&.\&. | select(\&.t? == \[dq]tr\[dq])\&.c | [\&.[]\&.c?[]]\[aq] examples/cbor\-examples\&.xhtml .EE .PP می‌توانیم مجموعه‌ای از آزمون‌ها را به صورت زیر ایجاد کنیم: .IP .EX jaq \[aq]\&.\&. | select(\&.t? == \[dq]tr\[dq])\&.c | [\&.[]\&.c?[]] | @json \[dq]jc(\[rs](\&.[0]), \[rs](\&.[1][2:]));\[dq]\[aq] \[rs] examples/cbor\-examples\&.xhtml \-r .EE .PP من دقیقاً از همین دستور برای ساخت پیش‌نویس آزمون‌های تجزیه CBOR در jaq استفاده کردم\&. .SH "نویسنده (AUTHOR)" .PP Michael Färber .SH "همچنین ببینید (SEE ALSO)" .PP \f[I]jq\f[R](1)