shlex --- تحلیل واژگانی ساده¶
کد منبع: Lib/shlex.py
کلاس shlex نوشتن تحلیلگرهای واژگانی برای سینتکسهای سادهای که شبیه سینتکس پوسته Unix هستند را آسان میکند. این امر اغلب برای نوشتن زبانهای کوچک (minilanguages) (برای مثال، در پروندههای کنترل اجرا برای برنامههای پایتون) یا برای تجزیه رشتههای داخل علامت نقلقول مفید خواهد بود.
ماژول shlex توابع زیر را تعریف میکند:
- shlex.split(s, comments=False, posix=True)¶
رشتهی s را با استفاده از سینتکس مشابه پوسته تقسیم میکند. اگر comments برابر
Falseباشد (پیشفرض)، تجزیهی کامنتها در رشتهی دادهشده غیرفعال خواهد شد (با تنظیم ویژگیcommentersدر نمونهیshlexبه رشتهی خالی). این تابع بهطور پیشفرض در حالت POSIX کار میکند، اما اگر آرگومان posix نادرست باشد، از حالت غیر POSIX استفاده میکند.تغییر یافته در نسخهی 3.12: اکنون ارسال
Noneبرای آرگومان s به جای خواندنsys.stdin، باعث پرتاب یک استثنا میشود.
- shlex.join(split_command)¶
توکنهای فهرست split_command را به هم میچسباند و یک رشته برمیگرداند. این تابع معکوس
split()است.>>> from shlex import join >>> print(join(['echo', '-n', 'Multiple words'])) echo -n 'Multiple words'
مقدار بازگشتی برای محافظت در برابر آسیبپذیریهای تزریق، برای پوسته خنثی شده است (به
quote()مراجعه کنید).اضافه شده در نسخهی 3.8.
- shlex.quote(s)¶
نسخهای خنثیشده برای پوسته از رشتهی s برمیگرداند. مقدار برگرداندهشده رشتهای است که میتواند با اطمینان بهعنوان یک توکن در خط فرمان پوسته استفاده شود؛ برای مواردی که نمیتوانید از یک فهرست استفاده کنید.
هشدار
ماژول
shlexفقط برای پوستههای Unix طراحی شده است.تضمین نمیشود که تابع
quote()روی پوستههای غیرسازگار با POSIX یا پوستههایی از سیستمعاملهای دیگر مانند ویندوز درست عمل کند. اجرای دستورهایی که توسط این ماژول نقلقول شدهاند روی چنین پوستههایی میتواند امکان آسیبپذیری تزریق دستور را ایجاد کند.استفاده از توابعی را در نظر بگیرید که آرگومانهای فرمان را با فهرستها منتقل میکنند، مانند
subprocess.run()باshell=False.این روش ناایمن خواهد بود:
>>> filename = 'somefile; rm -rf ~' >>> command = 'ls -l {}'.format(filename) >>> print(command) # executed by a shell: boom! ls -l somefile; rm -rf ~
quote()به شما امکان میدهد حفرهی امنیتی را ببندید:>>> from shlex import quote >>> command = 'ls -l {}'.format(quote(filename)) >>> print(command) ls -l 'somefile; rm -rf ~' >>> remote_command = 'ssh home {}'.format(quote(command)) >>> print(remote_command) ssh home 'ls -l '"'"'somefile; rm -rf ~'"'"''
نقلقولگذاری با پوستههای UNIX و با
split()سازگار است:>>> from shlex import split >>> remote_command = split(remote_command) >>> remote_command ['ssh', 'home', "ls -l 'somefile; rm -rf ~'"] >>> command = split(remote_command[-1]) >>> command ['ls', '-l', 'somefile; rm -rf ~']
اضافه شده در نسخهی 3.3.
ماژول shlex کلاس زیر را تعریف میکند:
- class shlex.shlex(instream=None, infile=None, posix=False, punctuation_chars=False)¶
یک نمونه از
shlexیا نمونهای از یک زیرکلاس، یک شیء تحلیلگر واژگانی است. آرگومان مقداردهی اولیه، در صورت وجود، مشخص میکند که نویسهها از کجا خوانده شوند. این آرگومان باید یک شیء شبهپرونده/جریانمانند با متدهایread()وreadline()یا یک رشته باشد. اگر آرگومانی داده نشود، ورودی ازsys.stdinگرفته خواهد شد. دومین آرگومان اختیاری یک رشتهی نام پرونده است که مقدار اولیه ویژگیinfileرا تنظیم میکند. اگر آرگومان instream حذف شود یا برابرsys.stdinباشد، این آرگومان دوم بهطور پیشفرض "stdin" خواهد بود. آرگومان posix حالت عملیاتی را تعریف میکند: وقتی posix درست نباشد (پیشفرض)، نمونهیshlexدر حالت سازگاری عمل خواهد کرد. هنگام عمل در حالت POSIX،shlexتلاش میکند تا حد ممکن به قوانین تجزیهی پوستهی POSIX نزدیک باشد. آرگومان punctuation_chars راهی فراهم میکند تا رفتار حتی به نحوهی تجزیهی پوستههای واقعی نزدیکتر شود. این آرگومان میتواند مقادیر مختلفی بپذیرد: مقدار پیشفرض،False، رفتار موجود در Python 3.5 و نسخههای قدیمیتر را حفظ میکند. اگر رویTrueتنظیم شود، تجزیهی نویسههای();<>|&تغییر میکند: هر دنبالهی پیوستهای از این نویسهها (که نویسههای نمادگذاری محسوب میشوند) بهصورت یک توکن واحد بازگردانده میشود. اگر روی یک رشتهی غیرخالی از نویسهها تنظیم شود، آن نویسهها بهعنوان نویسههای نمادگذاری استفاده خواهند شد. هر نویسهای در ویژگیwordcharsکه در punctuation_chars وجود داشته باشد، ازwordcharsحذف خواهد شد. برای اطلاعات بیشتر، بهبود سازگاری با پوستهها را ببینید. punctuation_chars فقط هنگام ایجاد نمونهیshlexقابل تنظیم است و نمیتوان آن را بعداً تغییر داد.تغییر یافته در نسخهی 3.6: پارامتر punctuation_chars افزوده شد.
همچنین ملاحظه نمائید
- ماژول
configparser پارسر برای پروندههای پیکربندی مشابه پروندههای
.iniویندوز.
اشیاء shlex¶
یک نمونه از shlex متدهای زیر را دارد:
- shlex.get_token()¶
یک توکن برمیگرداند. اگر توکنها با استفاده از
push_token()در پشته قرار گرفته باشند، یک توکن را از پشته خارج میکند. در غیر این صورت، یکی را از جریان ورودی میخواند. اگر خواندن بلافاصله با پایان پرونده مواجه شود،eofبرگردانده میشود (رشته خالی ('') در حالت غیر POSIX وNoneدر حالت POSIX).
- shlex.push_token(str)¶
آرگومان را روی پشتهی توکن قرار دهید.
- shlex.read_token()¶
یک توکن خام را بخوانید. پشتهی پسزدن (pushback stack) را نادیده بگیرید و درخواستهای منبع را تفسیر نکنید. (این معمولاً نقطهی ورود مفیدی نیست و تنها بهخاطر کامل بودن در اینجا مستند شده است.)
- shlex.sourcehook(filename)¶
هنگامی که
shlexیک درخواست منبع را تشخیص میدهد (بهsourceدر زیر مراجعه کنید)، این متد توکن بعدی را بهعنوان آرگومان دریافت میکند و انتظار میرود یک تاپل شامل یک نام پرونده و یک شیء شبهپرونده باز را برگرداند.بهطور معمول، این متد ابتدا هرگونه علامت نقلقول اطراف آرگومان را حذف میکند. اگر نتیجه یک مسیر مطلق باشد، یا هیچ درخواست منبع قبلیای فعال نباشد، یا منبع قبلی یک جریان (مانند
sys.stdin) باشد، نتیجه بدون تغییر باقی میماند. در غیر این صورت، اگر نتیجه یک مسیر نسبی باشد، بخش پوشه از نام پروندهای که بلافاصله قبل از آن در پشتهی درج منبع قرار دارد، به ابتدای آن افزوده میشود (این رفتار مشابه روشی است که پیشپردازندهی C با#include "file.h"برخورد میکند).نتیجهی دستکاریها بهعنوان یک نام پرونده در نظر گرفته میشود و بهعنوان اولین کامپوننت تاپل برگردانده میشود، و
open()روی آن فراخوانی میشود تا کامپوننت دوم را به دست دهد. (توجه: این، معکوس ترتیب آرگومانها در مقداردهی اولیه نمونه است!)این قلاب در دسترس قرار گرفته است تا بتوانید از آن برای پیادهسازی مسیرهای جستجوی پوشه، افزودن پسوندهای پرونده و سایر ترفندهای فضای نام استفاده کنید. هیچ قلاب 'close' متناظری وجود ندارد، اما یک نمونه از shlex، هنگامی که جریان ورودی منبع EOF را برگرداند، متد
close()آن را فراخوانی میکند.برای کنترل صریحتر پشتهسازی منبع، از متدهای
push_source()وpop_source()استفاده کنید.
- shlex.push_source(newstream, newfile=None)¶
یک جریان منبع ورودی را روی پشته ورودی قرار میدهد. اگر آرگومان filename تعیین شده باشد، بعداً برای استفاده در پیامهای خطا در دسترس خواهد بود. این همان متدی است که بهصورت داخلی توسط متد
sourcehook()استفاده میشود.
- shlex.pop_source()¶
آخرین منبع ورودی واردشده به پشته را از پشته ورودی بردارید. این همان متدی است که بهصورت داخلی هنگامی استفاده میشود که تحلیلگر واژگانی (lexer) در یک جریان ورودی پشتهای به EOF برسد.
- shlex.error_leader(infile=None, lineno=None)¶
این متد یک سرآغاز پیام خطا در قالب برچسب خطای کامپایلر C یونیکس تولید میکند؛ قالب بهصورت
'"%s", line %d: 'است، که در آن%sبا نام پرونده منبع جاری و%dبا شماره خط ورودی جاری جایگزین میشود (میتوان از آرگومانهای اختیاری برای بازنویسی این مقادیر استفاده کرد).این سهولت فراهم شده است تا کاربران
shlexتشویق شوند پیامهای خطا را در قالب استاندارد و قابلتجزیهای تولید کنند که Emacs و سایر ابزارهای Unix آن را درک میکنند.
نمونههای زیرکلاسهای shlex دارای چند متغیر نمونه عمومی هستند که یا تحلیل واژگانی را کنترل میکنند یا میتوان از آنها برای اشکالزدایی استفاده کرد:
- shlex.commenters¶
رشتهای از نویسهها که بهعنوان آغازگرهای توضیح شناخته میشوند. تمام نویسهها از آغازگر توضیح تا پایان خط نادیده گرفته میشوند. بهطور پیشفرض فقط شامل
'#'است.
- shlex.wordchars¶
رشتهای از نویسهها که برای تشکیل توکنهای چند نویسهای انباشته میشوند. بهطور پیشفرض، شامل تمام نویسههای الفباعددی ASCII و زیرخط میشود. در حالت POSIX، نویسههای لهجهدار در مجموعه Latin-1 نیز گنجانده میشوند. اگر
punctuation_charsخالی نباشد، نویسههای~-./*?=، که میتوانند در مشخصات نام پرونده و پارامترهای خط فرمان ظاهر شوند، نیز در این ویژگی گنجانده میشوند و هر نویسهای که درpunctuation_charsظاهر شود، در صورت وجود درwordchars، از آن حذف میشود. اگرwhitespace_splitرویTrueتنظیم شده باشد، این مورد بیاثر خواهد بود.
- shlex.whitespace¶
تویسههایی که فضای سفید در نظر گرفته میشوند و نادیده گرفته خواهند شد. فضای سفید مرز توکنها را مشخص میکند. بهطور پیشفرض، شامل فاصله، تب، تغذیه سطر و بازگشت به ابتدای سطر است.
- shlex.escape¶
نویسههایی که بهعنوان نویسههای خنثیکننده در نظر گرفته میشوند. این مورد فقط در حالت POSIX استفاده میشود و بهطور پیشفرض فقط شامل
'\'است.
- shlex.quotes¶
نویسههایی که بهعنوان علامتهای نقلقول رشته در نظر گرفته میشوند. توکن تا زمانی که دوباره همان علامت نقلقول مشاهده شود انباشته میشود (بنابراین، انواع مختلف علامتهای نقلقول، مانند پوسته، از یکدیگر محافظت میکنند). بهطور پیشفرض، شامل علامتهای نقلقول تکی و دوتایی ASCII است.
- shlex.escapedquotes¶
نویسههای موجود در
quotesکه نویسههای خنثیکنندهی تعریفشده درescapeرا تفسیر میکنند. این مورد فقط در حالت POSIX استفاده میشود و بهطور پیشفرض فقط شامل'"'است.
- shlex.whitespace_split¶
اگر
Trueباشد، توکنها فقط بر اساس فضای سفید جدا میشوند. این قابلیت مفید است، برای مثال، برای تجزیه سطرهای فرمان باshlexو دریافت توکنها به شیوهای مشابه آرگومانهای پوسته. هنگامی که همراه باpunctuation_charsاستفاده شود، توکنها علاوه بر آن نویسهها، بر اساس فضای سفید نیز جدا میشوند.تغییر یافته در نسخهی 3.8: ویژگی
punctuation_charsبا ویژگیwhitespace_splitسازگار شد.
- shlex.infile¶
نام پرونده ورودی فعلی، که در ابتدا در زمان نمونهسازی کلاس تنظیم شده یا توسط درخواستهای منبع بعدی روی پشته قرار گرفته است. بررسی این مقدار ممکن است هنگام ساخت پیامهای خطا مفید باشد.
- shlex.source¶
این ویژگی بهطور پیشفرض
Noneاست. اگر یک رشته به آن انتساب دهید، آن رشته بهعنوان یک درخواست درج در سطح واژگانی مشابه کلیدواژهsourceدر پوستههای مختلف تشخیص داده میشود. یعنی توکن بلافاصله بعدی بهعنوان نام پرونده باز میشود و ورودی تا EOF از آن جریان دریافت میشود؛ در آن نقطه، متدclose()آن جریان فراخوانی میشود و منبع ورودی دوباره جریان ورودی اصلی خواهد شد. درخواستهای منبع میتوانند تا هر تعداد سطحی روی هم انباشته شوند.
- shlex.debug¶
اگر این ویژگی عددی و
1یا بیشتر باشد، نمونهای ازshlexخروجی پیشرفت پرجزئیاتی دربارهی رفتار آن چاپ میکند. اگر نیاز به استفاده از این دارید، میتوانید کد منبع ماژول را بخوانید تا جزئیات را بیاموزید.
- shlex.lineno¶
شماره خط منبع (تعداد سطرهای جدید دیدهشده تاکنون بهعلاوه یک).
- shlex.token¶
بافر توکن (token buffer). ممکن است بررسی این مورد هنگام گرفتن استثناها مفید باشد.
- shlex.eof¶
توکنی که برای تعیین پایان پرونده به کار میرود. این مقدار در حالت غیر POSIX به رشتهی خالی (
'') و در حالت POSIX بهNoneتنظیم میشود.
- shlex.punctuation_chars¶
یک ویژگی فقطخواندنی. نویسههایی که بهعنوان نمادگذاری تلقی میشوند. دنبالههای پیوستهای از نویسههای نمادگذاری بهعنوان یک توکن واحد بازگردانده خواهند شد. با این حال، توجه داشته باشید که هیچگونه بررسی صحت معنایی انجام نخواهد شد: برای مثال، ممکن است '>>>' بهعنوان یک توکن بازگردانده شود، حتی اگر پوستهها آن را بهعنوان چنین توکنی نشناسند.
اضافه شده در نسخهی 3.6.
قواعد تجزیه¶
هنگام کار در حالت non-POSIX، shlex سعی میکند از قوانین زیر پیروی کند.
نویسههای نقلقول درون کلمات تشخیص داده نمیشوند (
Do"Not"Separateبهعنوان کلمهی واحدDo"Not"Separateتجزیه میشود)؛نویسههای خنثیسازی شناسایی نمیشوند؛
قرار دادن نویسهها درون علامتهای نقلقول، مقدار لفظی تمام نویسههای درون علامتهای نقلقول را حفظ میکند؛
علامتهای نقلقول پایانی، واژهها را جدا میکنند (
"Do"Separateبهصورت"Do"وSeparateتجزیه میشود)؛اگر
whitespace_splitبرابرFalseباشد، هر نویسهای که بهعنوان نویسه کلمهای، فضای سفید یا علامت نقلقول اعلام نشده باشد، بهصورت یک توکن تکنویسهای برگردانده میشود. اگرTrueباشد،shlexفقط کلمات را بر اساس فضای سفید جدا میکند؛EOF با یک رشته خالی (
'') اعلام میشود؛تجزیهی رشتههای خالی ممکن نیست، حتی اگر داخل علامت نقلقول باشند.
هنگام کار در حالت POSIX، shlex تلاش میکند از قواعد تجزیه زیر پیروی کند.
علامتهای نقلقول حذف میشوند و کلمات را جدا نمیکنند (
"Do"Not"Separate"بهعنوان کلمهی واحدDoNotSeparateتجزیه میشود)؛نویسههای خنثیسازی بدون علامت نقلقول (مثلاً
'\') مقدار لفظی نویسهای که پس از آنها میآید را حفظ میکنند؛قراردادن نویسهها درون علامتهای نقلقولی که بخشی از
escapedquotesنیستند (مانند"'") مقدار لفظی همه نویسههای درون علامتهای نقلقول را حفظ میکند؛دربرگرفتن نویسهها با علامتهای نقلقولی که بخشی از
escapedquotesهستند (مثلاً'"')، مقدار لفظی همه نویسههای درون علامتهای نقلقول را حفظ میکند، بهجز نویسههای ذکرشده درescape. نویسههای خنثیسازی معنای ویژه خود را فقط زمانی حفظ میکنند که پس از آنها علامت نقلقول مورد استفاده یا خود نویسه خنثیسازی بیاید. در غیر این صورت، نویسه خنثیسازی یک نویسه معمولی در نظر گرفته میشود.پایان پرونده با مقدار
Noneاعلام میشود؛رشتههای خالی داخل علامت نقلقول (
'') مجاز هستند.
بهبود سازگاری با پوستهها¶
اضافه شده در نسخهی 3.6.
کلاس shlex سازگاری با تجزیهای را فراهم میکند که پوستههای رایج یونیکس مانند bash، dash و sh انجام میدهند. برای بهرهمندی از این سازگاری، آرگومان punctuation_chars را در سازنده مشخص کنید. مقدار پیشفرض آن False است که رفتار پیش از 3.6 را حفظ میکند. با این حال، اگر روی True تنظیم شود، تجزیه نویسههای ();<>|& تغییر میکند: هر دنبالهای از این نویسهها بهعنوان یک توکن واحد بازگردانده میشود. هرچند این قابلیت بهاندازه یک پارسر کامل برای پوستهها نیست (که با توجه به تعدد پوستههای موجود، خارج از حیطه کتابخانه استاندارد خواهد بود)، اما به شما امکان میدهد پردازش سطرهای فرمان را آسانتر از آنچه در غیر این صورت ممکن بود انجام دهید. برای نمایش، میتوانید تفاوت را در قطعه کد زیر ببینید:
>>> import shlex
>>> text = "a && b; c && d || e; f >'abc'; (def \"ghi\")"
>>> s = shlex.shlex(text, posix=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b;', 'c', '&&', 'd', '||', 'e;', 'f', '>abc;', '(def', 'ghi)']
>>> s = shlex.shlex(text, posix=True, punctuation_chars=True)
>>> s.whitespace_split = True
>>> list(s)
['a', '&&', 'b', ';', 'c', '&&', 'd', '||', 'e', ';', 'f', '>', 'abc', ';',
'(', 'def', 'ghi', ')']
البته، توکنهایی برگردانده خواهند شد که برای پوستهها معتبر نیستند، و شما باید بررسیهای خطای خودتان را روی توکنهای برگرداندهشده پیادهسازی کنید.
بهجای ارسال True بهعنوان مقدار پارامتر punctuation_chars، میتوانید رشتهای با نویسههای مشخص را ارسال کنید که برای تعیین اینکه کدام نویسهها نمادگذاری محسوب میشوند، استفاده خواهد شد. برای مثال:
>>> import shlex
>>> s = shlex.shlex("a && b || c", punctuation_chars="|")
>>> list(s)
['a', '&', '&', 'b', '||', 'c']
توجه
هنگامی که punctuation_chars مشخص شده باشد، نویسههای ~-./*?= به ویژگی wordchars افزوده میشوند. دلیل آن این است که این نویسهها میتوانند در نام پروندهها (از جمله وایلدکارد) و آرگومانهای خط فرمان ظاهر شوند (برای مثال --color=auto). بنابراین:
>>> import shlex
>>> s = shlex.shlex('~/a && b-c --color=auto || d *.py?',
... punctuation_chars=True)
>>> list(s)
['~/a', '&&', 'b-c', '--color=auto', '||', 'd', '*.py?']
با این حال، برای تطبیق هرچه نزدیکتر با پوسته، توصیه میشود هنگام استفاده از punctuation_chars، همیشه از posix و whitespace_split استفاده شود؛ این کار wordchars را بهطور کامل بیاثر میکند.
برای بهترین نتیجه، punctuation_chars باید همراه با posix=True تنظیم شود. (توجه داشته باشید که posix=False برای shlex پیشفرض است.)