المسارات
/
jq
jq
/
التمارين
/
قائمة التسوق
قائمة التسوق

قائمة التسوق

تمرين تعلّمي

مقدمة

الأساسيات

سنفترض أنك على دراية بصيغة JSON وأنواع بياناتها.

يعمل jq بتمرير بيانات JSON الواردة عبر تعبير واحد (مكتوب على هيئة خط أنابيب من المُرشِّحات) للحصول على البيانات المحوّلة المطلوبة.

Note

لغة jq يُنفّذها برنامجُ jq. ويوفّر هذا البرنامج عدة خيارات مفيدة على سطر الأوامر للتحكم في كيفية استهلاك المُدخل وكيفية عرض المُخرج.

في الأمثلة أدناه ستُصادف:

  • -n أو --null-input

    عادةً يُعطى برنامج jq ملفًا ليقرأه، أو تُرسل بيانات إلى مُدخله. ويتيح لك الخيار --null-input توليد بيانات JSON دون أي مُدخلات.

  • -c أو --compact-output

    يطبع jq مُخرجه بتنسيق جميل افتراضيًا. ومن المفيد جدًا للبشر رؤية البيانات عندما تكون منسّقة بشكل جيد. لكن ذلك ليس ضروريًا للآلات: فخيار --compact-output يزيل المسافات البيضاء الخاصة بالتنسيق لتقليل حجم JSON الناتج.

  • -f filename أو --from-file filename

    اقرأ برنامج jq من filename بدلًا من تقديمه على سطر الأوامر. ويستخدم كل من sed وawk الخيار -f للغرض نفسه. وسترى هذا مستخدمًا في سكربتات الاختبار الخاصة بالتمارين التطبيقية.

ستركز بقية هذا الدرس على لغة jq.

المُرشِّحات والأنابيب

يُعرف المُرشِّح أيضًا باسم التعبير.

يأخذ المُرشِّح مُدخلًا وينتج مُخرجًا. وكما هو الحال عند العمل في صدفة يونكس، يمكنك ربط المُرشِّحات بأنبوب | لتوصيل مُخرج أحد المُرشِّحات بمُدخل آخر.

مُرشِّح الهوية: .

هذا أبسط مُرشِّح. إنه يمرّر مُدخله إلى مُخرجه ببساطة.

$ echo '[1, 2, 3]' | jq '.'
[
  1,
  2,
  3
]

المصفوفات

ستكون هذه مقدمة سريعة للتعامل مع المصفوفات. وسنغطي هذا الموضوع بمزيد من التفصيل لاحقًا.

يُوصَل إلى عناصر المصفوفة باستخدام الأقواس المربعة، وترقيمها يبدأ من الصفر.

$ echo '[10, 20, 30]' | jq '.[1]'
20

يمكن لـ المُرشِّح أن يبني مصفوفة بوضع تعبير بين [ و]

  • بقائمة معروفة من العناصر:

    jq -n '[1, 2, 3]'
    
  • لتجميع تدفق من العناصر: على سبيل المثال، range دالة تُخرج تدفقًا من الأعداد

    $ jq -n 'range(10; 70; 15)'
    10
    25
    40
    55
    

    واستخدام [] يجمع نتائج التعبير في مصفوفة

    $ jq -c -n '[range(10; 70; 15)]'
    [10,25,40,55]
    

الفاصلة عامل

الفاصلة ليست مجرد صياغة تفصل عناصر المصفوفة. الفاصلة عامل يضم التدفقات.

على سبيل المثال، [1, 2, 3] هو مُرشِّح يستخدم باني المصفوفة [] لجمع نتيجة ضم التعبيرات الثلاثة 1 و2 و3.

هل لاحظت الفواصل المنقوطة في range(10; 70; 15) أعلاه؟ ولأن الفواصل لها غرض محدد في لغة jq، تستخدم الدوال التي تأخذ عدة وسائط الفواصل المنقوطة للفصل بين الوسائط.

الكائنات

مقدمة سريعة إلى الكائنات.

على غرار كثير من لغات البرمجة، استخدم النقاط للوصول إلى خصائص الكائن

$ echo '{"foo": {"bar": "qux"}}' | jq '.foo.bar'
"qux"
Note

يمكن استخدام الأقواس المربعة مع الكائنات أيضًا، لكن حينها تلزم علامات الاقتباس للسلاسل النصية الحرفية. وهذه إحدى الطرق للتعامل مع المفاتيح التي تحتوي على مسافات.

$ echo '{"foo bar": "qux"}' | jq '.["foo bar"]'
"qux"

يمكنك بناء كائن باستخدام {} وأزواج key: value. ولا تلزم علامات الاقتباس حول المفاتيح التي تكون سلاسل نصية «بسيطة».

jq -n '{question: (6 * 9), answer: 42}'

يُخرج

{
  "question": 54,
  "answer": 42
}

لمعالجة المفتاح باعتباره تعبيرًا، عليك وضعه بين قوسين هلاليين (المثال التالي يُخرج أيضًا النتيجة نفسها أعلاه).

echo '[{"key":"question", "value":54}, {"key":"answer", "value":42}]' \
| jq '{(.[0].key): .[0].value, (.[1].key): .[1].value}'

خطوط الأنابيب

على سبيل المثال، لدينا file.json يحتوي على

{
  "key1": "value1",
  "key2": [5, 15, 25]
}

لنحسب طول المصفوفة key2:

$ jq '.key2 | length' file.json
3

نحن نمرّر مُخرج تعبير .key2 عبر الأنبوب كمُدخل إلى length، الذي يُخرج كما هو متوقع عدد العناصر في المصفوفة.

يمكن للمُرشِّحات تجاهل مُدخلها

في هذا المثال، تُتجاهَل بيانات JSON المُدخلة ولا تؤثر على المُخرج:

$ echo '{"answer": 42}' | jq '6 * 9'
54

يمكن للمُرشِّحات إخراج تدفقات من البيانات

يمكن لـ المُرشِّح أن يُخرج أكثر من قيمة. على سبيل المثال، يُخرج المُرشِّح .[] كل عنصر من المصفوفة كقيمة منفصلة:

$ jq -n -c '[1, 2, 3]'
[1,2,3]

$ jq -n -c '[1, 2, 3] | .[]'
1
2
3

وتمرير هذا المُرشِّح عبر الأنبوب إلى آخر سيُنفّذ المُرشِّح الثاني لكل قيمة:

$ jq -n -c '[1, 2, 3] | .[] | . * 2'
2
4
6

هذا يشبه التكرار الضمني. وبمجرد أن تفهم هذه التقنية، ستدرك أن مُرشِّحات jq القوية جدًا يمكن أن تكون موجزة جدًا.

الأقواس الهلالية

تُستخدم الأقواس الهلالية لتجميع التعابير الفرعية معًا لفرض ترتيب العمليات، تمامًا كما في اللغات الأخرى. وفي jq، قد تبدو الحاجة إليها مفاجئة إلى حد ما.

على سبيل المثال، لنفترض أننا نريد بناء مصفوفة بعنصرين: الجذر التربيعي للعدد 9؛ و_e_ مرفوعة إلى القوة 1. والتعبيران المنفردان هما 9 | sqrt و1 | exp. ونتوقع أن يكون المُخرج هو المصفوفة [3, 2.7...]

$ jq -n '[ 9|sqrt, 1|exp ]'
[
  20.085536923187668,
  2.718281828459045
]

لماذا لم نحصل على ما توقعناه؟ يفسّر jq ذلك على النحو التالي:

[ ((9|sqrt), 1) | exp ]

يبني jq تدفقًا من عنصرين (3 و1) يُعطى كل منهما إلى exp.

علينا أن نضمن أن exp يأخذ عددًا واحدًا فقط كمُدخل. بعبارة أخرى، علينا أن نفرض تقييم الأنبوب قبل الفاصلة.

$ jq -n '[ 9|sqrt, (1|exp) ]'
[
  3,
  2.718281828459045
]

الدوال والعوامل

دون الخوض في عمق كبير (ستكون الدوال موضوعًا لتمرين آخر)، إليك بعض الدوال المدمجة المفيدة:

  • length

    بمُدخل مصفوفة، أخرِج عدد العناصر في المصفوفة.

    $ jq -n '[10, 20, 30, 40] | length'
    4
    
  • +

    يفعل هذا العامل أشياء مختلفة حسب نوع القيم التي يعمل عليها: فهو يجمع الأعداد، ويصل السلاسل النصية، ويُضيف المصفوفات، ويدمج الكائنات.

    $ jq -c -n '
        3 + 4,
        "foo" + "bar",
        ["a", "b"] + ["c"],
        {"m": 10} + {"n": 20}
    '
    7
    "foobar"
    ["a","b","c"]
    {"m":10,"n":20}
    

    add دالة تأخذ مصفوفة وتُرجع عنصرًا جُمعت فيه كل العناصر معًا وفق قواعد +. و[1, 2, 3] | add يُخرج 6.

  • map

    بمُدخل مصفوفة ومُرشِّح كوسيط، أخرِج مصفوفة يُطبَّق فيها المُرشِّح على كل عنصر

    $ jq -c -n '[10, 20, 30, 40] | map(. / 5)'
    [2,4,6,8]
    
  • select

    بمُدخل ما ومُرشِّح كوسيط:

    • إذا أسفر تطبيق المُرشِّح على الوسيط عن قيمة صحيحة، أخرِج المُدخل دون تغيير
    • وإلا، أخرِج لا شيء (ليس القيمة null، بل لا مُخرج فعلًا)

    على سبيل المثال، بمُدخل بعض الأعداد، اختر تلك القابلة للقسمة على 3

    $ jq -n 'range(10) | select(. % 3 == 0)'
    0
    3
    6
    9
    

    تذكّر أن range يُخرج تدفقًا من الأعداد. وسيُستدعى select مرة لكل عدد. ولا تُخرَج إلا الأعداد «المارة» في التعبير.

    غالبًا ما تحتاج إلى اختيار عناصر من مصفوفة. وهناك عدة أساليب للقيام بذلك.

    بمُدخل ["Anne", "Bob", "Cathy", "Dave"]، اختر الأسماء التي طولها 4.

    • استخدم map وselect معًا

      map(select(length == 4))
      
    • فكّك المصفوفة إلى عناصر، ثم طبّق select على ذلك التدفق، واجمع النتائج

      [ .[] | select(length == 4) ]
      

التعليقات

تبدأ التعليقات بالمحرف # وتستمر إلى نهاية السطر.

التعليمات

لديك رغبة مفاجئة في أكل البان كيك. وبصفتك شخصًا عصريًا ذا ميول تقنية، تكتب قائمة تسوق لمكوّنات البان كيك بصيغة JSON. بنية القائمة هي:

{
  "name": "name of shopping list",
  "ingredients": [ ...list of ingredients... ],
  "optional ingredients": [ ...list of ingredients... ]
}

يُمثَّل المكوّن ككائن JSON، هكذا:

{
  "item": "flour",
  "amount": {
    "quantity": 2,
    "unit": "cup"
  }
}

للمكوّن خاصية اختيارية باسم "substitute" تحمل سلسلة نصية تمثل عنصرًا آخر يمكن استخدامه بدلًا منه.

لنرَ كيف يمكننا فحص قائمة التسوق باستخدام jq

1. استخراج اسم قائمة التسوق

اكتب تعبيرًا يُخرج عنصر "name" من قائمة التسوق.

2. احسب عدد المكوّنات المطلوبة

احسب المكوّنات "required" فقط. لا تُدرج المكوّنات الاختيارية.

3. كم كمية السكر؟

اكتب تعبيرًا يُخرج كمية السكر. المطلوب هو الجزء الرقمي فقط.

4. اربط المكوّنات القابلة للاستبدال

يمكن استبدال بعض المكوّنات (إذا لم يتوفر لديك المكوّن X يمكنك استخدام Y). أخرِج كائن JSON يربط كل مكوّن موصى به ببديله. أدرِج المكوّنات الاختيارية في الخريطة.

تعديل عبر GitHub يفتح الرابط في نافذة أو علامة تبويب جديدة
jq Exercism

مستعد لبدء قائمة التسوق؟

سجّل في Exercism لتتعلّم وتتقن jq عبر 12 مفهومًا75 تمرينًا، وإرشاد بشري حقيقي، وكل ذلك مجانًا.