مسیر
/
jq
jq
/
برنامه‌ی درسی
/
عبارات باقاعده
عب

عبارات باقاعده در jq

1 تمرین

درباره‌ی عبارات باقاعده

عبارات باقاعده (regex) دنباله‌هایی از کاراکترها هستند که یک الگوی جست‌وجو در متن را مشخص می‌کنند.

یادگیری نحوه‌ی نگارش عبارات باقاعده فراتر از حیطه‌ی این مبحث است. ما بر عبارت‌هایی تمرکز می‌کنیم که jq برای استفاده از عبارات باقاعده در اختیار می‌گذارد.

گونه‌ی عبارات باقاعده

ابزارهای مختلف نسخه‌های متفاوتی از عبارات باقاعده را پیاده‌سازی می‌کنند. jq کتابخانه‌ی regex Oniguruma را در خود دارد که تا حد زیادی با عبارات باقاعده‌ی Perl v۵.۸ سازگار است.

نحوه‌ی نگارش خاصی که jq استفاده می‌کند را می‌توان در مخزن GitHub پروژه‌ی Oniguruma پیدا کرد.

Caution

jq هیچ نحوه‌ی نگارش خاصی برای عبارات باقاعده ندارد. آن‌ها به‌سادگی به‌صورت رشته بیان می‌شوند. یعنی هر بک‌اسلشی که در عبارت باقاعده هست باید در رشته escape شود.

برای مثال، کلاس کاراکتر رقم (\d) باید به‌صورت "\\d" نوشته شود.

توابع عبارات باقاعده

عبارات باقاعده در jq محدود به مجموعه‌ای از فیلترها است.

تطبیق ساده

وقتی می‌خواهید بدانید رشته‌ای با الگویی مطابقت دارد یا نه، از فیلتر test استفاده کنید.

STRING | test(REGEX)
STRING | test(REGEX; FLAGS)
STRING | test([REGEX, FLAGS])

این فیلتر یک نتیجه‌ی منطقی به‌عنوان خروجی می‌دهد.

"Hello World!" | test("W")    # => true
"Goodbye Mars" | test("W")    # => false

اطلاعاتی درباره‌ی تطبیق

وقتی می‌خواهید زیررشته‌ای را بیرون بکشید که واقعاً با الگو مطابقت داشته، از فیلتر match استفاده کنید.

STRING | match(REGEX)
STRING | match(REGEX; FLAGS)
STRING | match([REGEX, FLAGS])

این فیلتر این موارد را به‌عنوان خروجی می‌دهد:

  • اگر تطبیقی وجود نداشته باشد، هیچ‌چیز، یا
  • اگر تطبیقی وجود داشته باشد، شیئی که شامل ویژگی‌های گوناگون است.

این مثال با استفاده از نحوه‌ی نگارش backref، یعنی \1، دو واکه‌ی یکسان پشت‌سرهم را جست‌وجو می‌کند.

"Hello World!" | match("([aeiou])\\1")
# => empty

"Goodbye Mars" | match("([aeiou])\\1")
# => {
#      "offset": 1,
#      "length": 2,
#      "string": "oo",
#      "captures": [
#        {
#          "offset": 1,
#          "length": 1,
#          "string": "o",
#          "name": null
#        }
#      ]
#    }

فیلتر match برای هر تطبیق یک شیء برمی‌گرداند. این مثال کاربرد پرچم "g" را برای یافتن همه‌ی واکه‌ها نشان می‌دهد.

"Goodbye Mars" | match("[aeiou]"; "g")
# => { "offset": 1, "length": 1, "string": "o", "captures": [] }
#    { "offset": 2, "length": 1, "string": "o", "captures": [] }
#    { "offset": 6, "length": 1, "string": "e", "captures": [] }
#    { "offset": 9, "length": 1, "string": "a", "captures": [] }

زیررشته‌های ضبط‌شده

فیلتر capture مانند فیلتر match در صورت وجود تطبیق یک شیء برمی‌گرداند.

STRING | capture(REGEX)
STRING | capture(REGEX; FLAGS)
STRING | capture([REGEX, FLAGS])

شیء برگردانده‌شده نگاشتی از ضبط‌های نام‌دار است.

"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")
# => {
#      "project": "JIRAISSUE",
#      "issue_num": "1234"
#    }

فقط زیررشته‌ها

فیلتر scan شبیه match با پرچم "g" است.

STRING | scan(REGEX)
STRING | scan(REGEX; FLAGS)

# note, there is no scan([REGEX, FLAGS]) version, unlike other filters

scan یک جریان از زیررشته‌ها را به‌عنوان خروجی می‌دهد.

"Goodbye Mars" | scan("[aeiou]")
# => "o"
#    "o"
#    "e"
#    "a"

برای ضبط زیررشته‌ها از سازنده‌ی آرایه‌ی [...] استفاده کنید.

"Goodbye Mars" | [ scan("[aeiou]") ]
# => ["o", "o", "e", "a"]

شکستن یک رشته

اگر بخش‌هایی از رشته را که می‌خواهید نگه دارید می‌دانید، از match یا scan استفاده کنید. اگر بخش‌هایی را که می‌خواهید دور بریزید می‌دانید، از split استفاده کنید.

STRING | split(REGEX; FLAGS)
Caution

فیلتر split با ۱ آرگومان، آرگومان خود را به‌عنوان یک رشته‌ی ثابت در نظر می‌گیرد.

برای استفاده از یک regex با split، باید آرگومان دوم را بدهید؛ استفاده از یک رشته‌ی خالی اشکالی ندارد.

مثالی که یک رشته را بر اساس فاصله‌های سفید دلخواه تقسیم می‌کند.

"first   second           third fourth" | split("\\s+"; "")
# => ["first", "second", "third", "fourth"]
Note

این چیزی است که اگر آرگومان پرچم‌ها را فراموش کنیم اتفاق می‌افتد.

"first   second           third fourth" | split("\\s+")
# => ["first   second           third fourth"]

فقط یک نتیجه: رشته‌ی ثابت \s+ در ورودی دیده نشد.

فیلتر split با ۱ آرگومان نمی‌تواند با فاصله‌های سفید دلخواه کنار بیاید. تقسیم بر اساس یک فاصله این نتیجه را می‌دهد.

"first   second           third fourth" | split(" ")
# => ["first", "", "", "second", "", "", "", "",
#     "", "", "", "", "", "", "third", "fourth" ]

جایگزینی‌ها

فیلترهای sub و gsub می‌توانند رشته‌ی ورودی را تغییر دهند و بخش‌های مطابق‌شده‌ی ورودی را با یک رشته‌ی جایگزین عوض کنند.

برای جایگزینی فقط اولین تطبیق، از sub استفاده کنید. برای جایگزینی همه‌ی تطبیق‌ها، از gsub استفاده کنید.

STRING | sub(REGEX; REPLACEMENT)
STRING | sub(REGEX; REPLACEMENT; FLAGS)
STRING | gsub(REGEX; REPLACEMENT)
STRING | gsub(REGEX; REPLACEMENT; FLAGS)
"Goodnight kittens. Goodnight mittens." | sub("night"; " morning")
# => "Good morning kittens. Goodnight mittens."

"Goodnight kittens. Goodnight mittens." | gsub("night"; " morning")
# => "Good morning kittens. Good morning mittens."

متن جایگزین می‌تواند به زیررشته‌های مطابق‌شده اشاره کند؛ از ضبط‌های نام‌دار و درون‌یابی رشته استفاده کنید.

"Some 3-letter acronyms: gnu, csv, png"
| gsub( "\\b(?<tla>[[:alpha:]]{3})\\b";     # find words 3 letters long
        "\(.tla | ascii_upcase)" )          # upper-case the match
# => "Some 3-letter acronyms: GNU, CSV, PNG"

پرچم‌ها

در همه‌ی فیلترهای بالا، FLAGS رشته‌ای است که از صفر یا چند مورد از پرچم‌های پشتیبانی‌شده تشکیل می‌شود.

  • g - جست‌وجوی سراسری (همه‌ی تطبیق‌ها را پیدا می‌کند، نه فقط اولین مورد)
  • i - جست‌وجوی بدون توجه به بزرگی و کوچکی حروف
  • m - حالت چندخطی ('.' با خطوط جدید هم مطابقت می‌کند)
  • n - نادیده گرفتن تطبیق‌های خالی
  • p - هم حالت s و هم حالت m فعال می‌شوند
  • s - حالت تک‌خطی ('^' -> '\A', '$' -> '\Z')
  • l - یافتن طولانی‌ترین تطبیق‌های ممکن
  • x - قالب توسعه‌یافته‌ی regex (فاصله‌های سفید و توضیحات نادیده گرفته می‌شوند)

برای مثال

"JIRAISSUE-1234" | capture("(?<project>\\w+)-(?<issue_num>\\d+)")

# or with Extended formatting

"JIRAISSUE-1234" | capture("
                     (?<project>   \\w+ )  # the Jira project
                     -                     # followed by a hyphen
                     (?<issue_num> \\d+ )  # followed by digits
                   "; "x")
ویرایش از طریق GitHub این پیوند در پنجره یا زبانه‌ی جدیدی باز می‌شود

عبارات باقاعده را یاد بگیرید

تمرین کردن قفل شده است

برای تمرین عبارات باقاعده قفل 1 تمرین دیگر را باز کنید