تبدیل رشته به لیست در پایتون یکی از عملیات اساسی در برنامه‌های مربوط به پروژه‌های واقعی است. این فرایند به اجرای عملیات گوناگون بر روی داده‌های متنی بسیار کمک می‌کند و به روش‌های مختلفی قابل اجرا است. برای مثال، می‌توان به استفاده از متد split()

اشاره کرد. این متد برای جداسازی اعضای تشکیل دهنده «رشته» (String) بر اساس جداکننده‌‌ای که تعیین شده یا تبدیل هر کلمه به‌صورت جداگانه به عنصری در لیست به‌کار می‌رود. چنین تغییراتی در رشته‌های پایتون، پردازش، تحلیل و استخراج اطلاعات مفید از داده‌های متنی را بسیار ساده‌تر می‌کنند. این کار عملیاتی بسیار ساده است که خوانایی کد را بالاتر می‌برد و مدیریت رشته‌ها را کارآمدتر می‌کند. در این مطلب از مجله فرادرس با همه روش‌های ممکن برای تبدیل رشته به لیست کار خواهیم کرد. تسلط به کار با این روش‌ها در پروژه‌های گوناگونی، از طراحی بَکِند اپلیکیشن‌های اینترنتی گرفته تا تحلیل داده و حتی آماده‌سازی داده‌ها برای یادگیری مدل‌های شبکه عصبی، کاربرد دارند.

فهرست مطالب این نوشته

چه روش هایی برای تبدیل رشته به لیست در پایتون وجود دارند؟

روش‌های مختلفی برای تبدیل رشته به لیست در پایتون وجود دارند که در این مطلب به بعضی از آن‌ها اشاره و برای هر کدام مثال‌های مختلفی را کدنویسی کرده‌ایم. این روش‌ها شامل استفاده از انواع تکنیک‌ها و متدها در پایتون مانند موارد زیر می‌شوند.

  • استفاده از متد split()
  • استفاده از متد list()
  • استفاده از تابع re.findall()
  • استفاده از تکنیک List Comprehension مخصوص تعریف لیست‌ها
  • استفاده از تکنیک «قطعه‌قطعه‌سازی لیست‌» (String Slicing)
  • و غیره

استفاده از متد split برای تبدیل رشته به لیست در پایتون

تبدیل رشته به لیست در پایتون با استفاده از متد split()

باعث تقسیم رشته به زیررشته‌ها بر اساس جداکننده‌ می‌شود. متد split()

به عنوان ورودی فقط یک آرگومان تابعی می‌گیرد و آن‌ هم همان جداکننده بین زیررشته‌ها است. این جداکننده کاراکتری است که مرز بین هر عنصر را برای تشکیل لیست نهایی تعریف می‌کند. اگر هیچ جداکننده‌ای مشخص نشود، این متد به‌صورت پیش‌فرض کاراکتر «فضای خالی» (Whitespace) را به عنوان جداکننده عناصر رشته اصلی در نظر می‌گیرد.

دختر برنامه‌نویس در تاریکی شب در حال کدنویسی است

برای مثال، رشته “Python is awesome”

 را در نظر بگیرید. برای اینکه این رشته را به کلمات تشکیل دهنده آن تجزیه کنیم باید کدی به‌ شکل زیر بنویسیم.

1my_string = "Python is awesome"
2my_list = my_string.split()
3print(my_list)

این کد رشته را به این شکل [‘Python’, ‘is’, ‘awesome’]

 به لیستی از کلمات تشکیل‌دهنده آن تقسیم می‌کند.

اگر بخواهیم که رشته‌ای را با کاراکتر خاص دیگری به غیر از فضای خالی –مانند کاراکتر ویرگول یا کاما ,

 - به عنوان جداکننده تجزیه کنیم باید این کاراکتر را به عنوان آرگومان جداکننده به متد split()

ارسال کنیم. برای نمونه، برای اینکه رشته “Python,is,awesome”

 را بر اساس کاراکتر کاما از هم تجزیه کنیم باید طبق شکل زیر کد بنویسیم.

1my_string = "Python,is,awesome"
2my_list = my_string.split(',')
3print(my_list)

کد بالا لیستی به شکل [‘Python’, ‘is’, ‘awesome’]

 تولید خواهد کرد.

برای تجزیه داده‌های درون دورن فایل‌ متنی یا داده‌های ورودی کاربر که عناصر تشکیل دهنده آن‌ بر اساس کاراکترهای خاصی از هم جدا شده‌اند، متد split()

به‌طور خاص، استفاده می‌شود. این خاصیت متد split()

مدیریت و کار با داده‌ها را به‌طرز موثری ساده می‌سازد.

برای آموختن حرفه‌ ای پایتون چکار کنیم؟

بهترین روش آموختن پایتون شرکت در کلاس‌هایی است که اساتید مجرب به‌صورت تصویری فرآیند نوشتن و اجرای کدها را به شما نشان دهند. اما باید توجه کرد کلاس‌های کامل و حرفه‌ای علاوه بر هزینه بالایی که بر دانشجویان تحمیل می‌کنند، دارای چهارچوب زمانی خاصی نیز هستند. بنابراین پیدا کردن کلاسی که با زمان آزاد ما هماهنگ باشد کمی دشوار خواهد بود.

پس بهترین راه استفاده از فیلم‌های آموزشی است. سایت فرادرس فیلم‌های بسیار خوبی با کیفیت عالی در روش آموزش و متناسب با همه سطوح دانش را برای دانشجویان فراهم کرده است. در صورتی که در اوایل مسیر یادگیری پایتون هستید دوره‌های آموزشی زیر برای شما عالی هستند.

مجموعه آموزش پایتون

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

چگونه با استفاده از تابع list رشته را به لیست تبدیل کنیم؟

می‌توانیم برای اینکه با استفاده از متد list()

عملیات تبدیل رشته به لیست را انجام دهیم هر کاراکتر درون رشته را به عنصر مجزایی در لیست تبدیل کنیم. تابع list()

رشته‌ای را به عنوان آرگومان دریافت می‌کند و در خروجی لیستی جدیدی بر می‌گرداند که یک به یک کاراکترهای تشکیل دهنده رشته را به‌صورت مجزا به عنوان عناصر خود شامل می‌شود.

برای نمونه، اگر رشته‌ای به شکل “Python”

در اختیار داشته باشیم، عملیات تبدیل کردن این رشته به لیستی از رشته‌ها، شبیه به کدی که در ادامه آمده خواهد بود.

1my_string = "Python"
2my_list = list(my_string)
3print(my_list)

این تکه کد کوچک در خروجی لیستی به شکل [‘P’, ‘y’, ‘t’, ‘h’, ‘o’, ‘n’]

 را بر می‌گرداند.

متد list()

در پایتون به‌طور خاص، وقتی کاربرد خواهد داشت که نیاز به اجرای عملیات بر روی هر کاراکتر از رشته دریافت شده، به‌صورت مجزا داشته باشیم. برای مثال می‌توان از عملیاتی مانند شمارش تعداد رخداد کاراکترهای خاصی، جای‌گذاری کاراکتر‌های مشخص شده با کاراکترهای دیگر یا هر نوع از کار با رشته‌های در سطح کاراکتر را نام برد. این تابع روش ساده‌ای را برای شکستن هر رشته به کاراکترهای تشکیل دهنده آن فراهم می‌کند. این کار به منظور انجام پردازش‌ بر روی هر کاراکتر به‌صورت مجزا انجام می‌شود.

برای اینکه بتوانید از مطالب آموخته شده در محیط‌های واقعی و بازار کار استفاده کنید بهتر است که فیلم‌های آموزشی درباره انواع کاربردهای پایتون را نیز ببینید. به عنوان مثال، از میان نمونه‌های زیادی که وجود دارند پیشنهاد می‌کنیم فیلم‌های آموزشی مربوط به تجزیه و تحلیل داده های مالی با پایتون یا آموزش فریمورک تحت وب Django را در وب‌سایت آموزشی فرادرس، مشاهده کنید.

تکنیک List Comprehension برای تبدیل رشته به لیست در پایتون

برای اینکه با استفاده از تکنیک List Comprehension بتوانیم رشته‌ای را به لیست در پایتون تبدیل کنیم، باید بر روی همه کاراکترهای تشکیل دهنده لیست پیمایش کنیم. سپس به هر کاراکتری که می‌رسیم، به عنوان عنصری مجزا، این کارکتر را به لیست جدید اضافه کنیم. عملیات List Comprehension سینتکس مختصری را به این منظور فراهم کرده است. سینتکسی که به‌صورت مستقیم و خوانا عملیات تبدیل رشته به لیست را توضیح می‌دهد.

به‌عنوان مثال، برای اینکه رشته “Hello”

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

1my_string = "Python"
2my_list = list(my_string)
3print(my_list)

کد بالا لیستی به شکل [‘H’, ‘e’, ‘l’, ‘l’, ‘o’]

 را به عنوان خروجی بر می‌گرداند.

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

1my_string = "Hello"
2my_list = [character for character in my_string if my_string.count(character) == 1]
3print(my_list)

با اعمال این شرط در متن تکنیک List Comprehension لیست جدید به شکل [‘H’, ‘e’, ‘o’]

 در اثر اجرای کد ساخته خواهد شد. همان‌طور که می‌بینید در این لیست جدید کاراکتر تکراری ‘l’

 حذف شده است.

پسری در حال کار با کامپیوتر در مقابل پنجره‌ای رو به کوهستان نشسته است.

استفاده از تکنیک List Comprehension برای تبدیل رشته به لیست نه تنها کد را ساده‌تر می‌کند بلکه حتی فرایند پردازش عناصر رشته را هم انعطاف‌پذیرتر می‌کند. استفاده از این تکنیک، عملیاتی مانند فیلتر کردن یا اعمال توابع بر روی هر کاراکتر به‌صورت جداگانه را در طول اجرای فرایند تبدیل ممکن می‌کند.

تبدیل رشته به لیست در پایتون با کمک String Slicing

لیستی ایجاد کنید که شامل قسمت‌های مشخصی از رشته باشد. با استفاده از تکنیک «تکه‌سازی رشته‌ها» (String Slicing)، نقاط شروع و انتهای قسمت‌هایی از رشته که باید به‌صورت عنصر در لیست قرار بگیرند مشخص می‌شود. در حالی که عملیات Slicing در رشته‌ها به‌طور معمول برای استخراج قسمت‌های خاصی از رشته -«زیررشته» (Substring)- به‌کار می‌رود، ترکیب این روش با یکی از مکانیزم‌های حلقه، برای مثال حلقه for

 یا تکنیک List Comprehension می‌تواند کمک کند که لیست‌هایی با ساختارهای پیچیده‌تری بر مبنای رشته دریافت شده ایجاد کنیم.

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

1my_string = "Python"
2my_list = [my_string[i:i+2] for i in range(0, len(my_string), 2)]
3print(my_list)

این کد رشته “Python”

 را به لیستی از «زیررشته‌ها» (Substrings) تقسیم می‌کند که هر کدام شامل دو کاراکتر می‌شوند. خروجی کد به شکل [‘Py’, ‘th’, ‘on’]

 است.

تکنیک Slicing رشته‌ها در زبان برنامه‌نویسی پایتون بسیار پرکاربرد است. این تکنیک نه تنها ساخت لیست به‌صورت کاراکتر به کاراکتر را به سادگی ممکن می‌سازد بلکه بر اساس نیازهای خاص می‌تواند عملیات تقسیم رشته را با ریزه‌کاری‌های خاصی نیز انجام دهد. این تکنیک به‌طور ویژه در پردازش رشته‌ها با شرایط خاص کاربرد دارد. برای مثال می‌توان به زمان‌هایی که اندازه هر کدام از عناصر لیست باید کنترل شود یا اندازه عناصر با یکدیگر متفاوت‌اند اشاره کرد. تکنیک Slicing رشته‌ها دقت بالای کار را در تبدیل داده‌های رشته‌ای به شکل لیست تضمین می‌کند.

تبدیل رشته به لیست در پایتون با استفاده از متد re.findall

برای اینکه با استفاده از متد re.findall()

بتوان رشته‌ای را به لیست تبدیل کرد باید از «عبارات منظم» (Regular Expressions) برای شناسایی و استخراج الگوهای مشخص شده کاراکترها از درون رشته استفاده کرد. متد re.findall()

درون ماژول re

 تعریف شده است. این کتابخانه به‌صورت اختصاصی برای کار با رجکس‌ها در پایتون ایجاده شده است. در صورت نیاز به کسب اطلاعات بیشتر درباره رجکس‌ها می‌توانید به مطلب RegEx چیست از مجله فرادرس رجوع کنید. کتابخانه re

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

برای مثال، برای استخراج همه کلمات درون رشته بدون در نظر گرفتن فضای خالی و علائم نگارشی می‌توانیم از کد زیر استفاده کنیم.

1import re
2
3my_string = "Hello, Python 3.8!"
4my_list = re.findall(r'bw+b', my_string)
5print(my_list)

این کد رشته [‘Hello’, ‘Python’, ‘3’, ‘8’]

 را در خروجی نمایش می‌دهد. که در واقع به‌صورت موثری رشته اصلی را به لیستی از عناصری سازنده آن تبدیل کرده است. این عناصر شامل همه زیر رشته‌هایی که شبیه به کلمات باشند یعنی حتی اعداد مجزا نیز می‌شود.

متد re.findall()

نیز یکی از متدهای پرکاربرد در بحث بردازش رشته است. این متد کمک می‌کند که نوع خاصی از داده‌ها مثل همه حروف الفای بزرگ، رقم‌ها، آدرس‌های ایمیل یا هر نوع الگوی دیگری را از درون رشته استخراج کنیم. برای نمونه، به کد زیر نگاه کنید. عبارت منظم درون این کد به‌صورتی طراحی شده که فقط ارقام درون رشته دریافت شده را استخراج می‌کند.

1import re
2
3my_string = "Version 3.8 was released on October 14, 2019"
4my_list = re.findall(r'd+', my_string)
5print(my_list)

تکه کدی که در بالا می‌بینید خروجی به شکل [‘3’, ‘8’, ’14’, ‘2019’]

 را تولید می‌کند. این کد نشان می‌دهد که چگونه می‌توان متد re.findall()

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

استفاده از تابع enumerate برای تبدیل رشته به لیست در پایتون

با استفاده از تابع enumerate()

 هر کاراکتر را با شماره ایندکس متناظرش درون رشته جفت می‌کنیم. سپس به کمک این شماره‌ها می‌توان به‌سادگی لیستی از همه کاراکترهای تشکیل دهنده رشته بدست آورد. تابع enumerate()

به شی پیمایش‌پذیر شمارنده‌ای اضافه می‌کند. این شی پیمایش‌پذیر می‌تواند یک رشته باشد. در نهایت هم داده‌های درون آن رشته را در شکل اشیا Enumerate شده بر می‌گرداند. مثالی از اشیا Enumerate شده را در ادامه خواهیم دید.

دانشآموزی با کوله پشتی بر روی کمر در حال کار با لپتاپ است.

این تکنیک به‌صورت خاص زمانی کاربرد دارد که بخواهیم رد موقعیت قرار گیری همه عناصر وارد شده به لیست را در رشته اصلی حفظ کنیم. برای اینکه رشته “hello”

 را به لیستی از تاپل‌ها تبدیل کنیم، می‌توانیم از کدی که در ادامه آمده استفاده کنیم. در اینجا هر تاپلی شامل کاراکتر و ایندکس موقعیت قرارگیری آن کاراکتر در رشته اصلی است. در واقع این تاپل‌ها همان شی Enumerate هستند.

1my_string = "hello"
2my_list = list(enumerate(my_string))
3print(my_list)

خروجی کد بالا با رشته دلخواه داده شده، به شکل زیر خواهد بود.

[(0, 'h'), (1, 'e'), (2, 'l'), (3, 'l'), (4, 'o')]

در این خروجی هر تاپل شامل ایندکسی به همراه مقدار درون آن ایندکس از رشته است.

استفاده مستقیم از تابع enumerate()

برای تبدیل رشته به متن باعث تولید لیستی از تاپل‌ها می‌شود که به‌صورت جفت کاراکتر و ایندکس متناظر هر کاراکتر در متن است. علاوه براین، این تابع می‌تواند برای حل سناریوهای پیچیده‌تری نیز سازگار شود. برای مثال، سناریو‌هایی که در آن‌ها دانستن موقعیت هر عنصر در رشته ضروری است. به عنوان نمونه، اگر نیاز داشته باشیم که عناصر تشکیل دهنده رشته را بر حسب جایگاه‌شان در رشته، فیلتر یا در عملیات خاصی استفاده کنیم یا در مسائلی از این قبیل، استفاده تابع enumerate()

 بسیار کار‌آمد خواهد بود.

چگونه با استفاده از JSON در پایتون رشته ای را به لیست تبدیل کنیم؟

برای تبدیل رشته به لیست در پایتون با استفاده از JSON باید از تابع json.loads()

 استفاده کنیم. تابع json.loads()

در کتابخانه json

 تعریف شده است. روش JSON به وضوح در کار با رشته‌های در شکل خاص آرایه‌های JSON، کاربرد دارد. کلمه JSON مخفف عبارت «JavaScript Object Notation» به معنای «نشانه‌گذاری اشیا جاوا-اسکریپتی» است. JSON شکل سبکی از فایل‌ها برای انتقال داده‌ است. در این روشِ انتقال داده، خواندن و نوشتن داده‌ها برای انسان ساده است. به همچنین کامپیوترها نیز به‌سادگی می‌توانند فایل‌های JSON را درک کنند و ایجاد کنند.

وقتی رشته‌ای نمایانگر آرایه‌ای از جنس JSON در پایتون باشد، با استفاده از این روش به‌طور مستقیم می‌تواند به لیست تبدیل شود. برای نمونه، اگر رشته‌ای در اختیار داشته باشیم که نمایانگر آرایه‌ای از جنس JSON مانند ‘[“Python”, “Java”, “C++”]’

 است. به‌سادگی با استفاده از کدی مانند کد زیر می‌توانیم این رشته را به لیست پایتونی تبدیل کنیم.

1import json
2
3my_string = '["Python", "Java", "C++"]'
4my_list = json.loads(my_string)
5print(my_list)

خروجی کد بالا با رشته دریافت شده، لیستی به شکل [‘Python’, ‘Java’, ‘C++’]

 است.

در مواردی که داده‌ها از طریق Web API-ها بدست آمده‌ یا در فایل‌هایی به شکل JSON ذخیره شده‌اند، استفاده از روش json.loads()

برای تبدیل رشته به لیست به‌طور بسیار مناسبی کارآمد خواهد بود. این روش با کمک به کار و پردازش بیشتر و بهتر داده‌ها، روشی بسیار ساده برای تبدیل رشته‌های آرایه JSON به لیست‌های پایتونی در نظر گرفته می‌شود.

استفاده از تابع ast.literal برای تبدیل رشته به لیست در پایتون

در پایتون با استفاده از تابع ast.literal_eval()

می‌توانیم رشته‌ها را به‌صورت بسیار امنی به لیست تبدیل کنیم. این تابع برای ارزیابی رشته‌ای که می‌تواند شامل نمایش عینی عناصر برنامه نویسی یا ظرفی حاوی این عناصر باشد به‌کار گرفته می‌شود. به این معنی که رشته‌هایی که این تابع می‌پذیرد می‌توانند حاوی کدهای برنامه‌نویسی یا حتی یک برنامه کامل باشند. تابع ast.literal_eval()

امنیت داده‌ها را در حین اجرای عملیات تبدیل تضمین می‌کند. تابع ast.literal_eval()

درون کتابخانه ast

 تعریف شده است. کلمه «ast» مخفف عبارت «Abstract Syntax Trees» است. این کتابخانه برای پردازش امن داده‌ها در رشته‌هایی تعریف شده است که شامل ساختارهای ذخیره داده پایتون هستند. یعنی این متد برای کار با رشته‌هایی به‌کار می‌رود که شامل لیست‌ها، تاپل‌ها، دیکشنری‌های پایتون و سایر انواع داده‌ای درونی هستند.

لپتاپ روشنی که در صفحه نمایشش عکس کوهستان است بر روی میز قرار دارد

برای مثال، اگر رشته‌ای داشته باشیم که نشان‌دهنده لیستی باشد یا در واقع درون این رشته یک لیست مانند ‘[“apple”, “banana”, “cherry”]’

 قرار داشته باشد. با استفاده از کدی به شکل کد پیاده‌سازی شده پایین می‌توانیم این رشته را به لیست تبدیل کنیم.

1import ast
2
3my_string = '["apple", "banana", "cherry"]'
4my_list = ast.literal_eval(my_string)
5print(my_list)

خروجی لیست بالا به شکل [‘apple’, ‘banana’, ‘cherry’]

 است.

تابع ast.literal_eval()

گزینه جایگزین امنی برای تابع eval()

است. تابع eval()

برای ارزیابی رشته‌های شامل عبارات پایتون به‌کار می‌رود. از آنجا که تابع ast.literal_eval()

بدون اجرای کدهای درون رشته، فقط مقادیر محتوای رشته را پردازش می‌کند پس از بروز بسیاری از خطرات امنیتی جلوگیری می‌کند که در استفاده از تابع eval()

پیش می‌آیند.

تابع ast.literal_eval()

آموزش های تکمیلی پایتون

در این بخش از مطلب به آموزش‌های تکمیلی پایتون می‌پردازیم. یکی از روش‌های بسیار مناسب برای تقویت مهارت در یادگیری هر زبان برنامه‌نویسی و تکنولوژی دیگری، مطالعه این زبان‌هاو تکنولوژی‌ها در بستر پروژه‌های واقعی است. برای اینکه بتوانیم به بهترین شکل ممکن داده‌های آموخته شده را ارزیابی کنیم باید بتوانیم کارایی آن‌ها را در دنیای واقعی بسنجیم. در ادامه چند مورد از فیلم‌های آموزشی فرادرس را درباره آموزش‌های پروژه محور پایتون معرفی کرده‌ایم.

مجموعه آموزش‌های پروژه محور پایتون

جمع بندی

عملیات تبدیل رشته به لیست در پایتون به روش‌های مختلفی قابل اجرا است. هر کدام از این روش‌ها در ارتباط با نوع داده‌ها و موقعیت‌های مختلف می‌توانند بهترین عملکرد را داشته باشند. در این مطلب از مجله فرادرس درباره انواع روش‌های ممکن برای اجرای این عملیات صحبت کردیم.

می‌توانیم از متدهایی مانند split()

برای اجرای ساده عمل تبدیل رشته به لیست با توجه به جداکننده مورد نظر زیررشته‌ها از هم استفاده کنیم. از تابع list()

برای ساخت لیست‌هایی بر مبنای کاراکتر به کاراکتر رشته‌ها، تکنیک List Comprehension برای اجرای عملیات با پیچیدگی بیشتر، تابع re.findall()

برای استخراج زیر رشته‌ها بر اساس الگو، روش JSON برای پردازش رشته‌های JSON یا از تابع ast.literal_eval()

برای ارزیابی امن داده‌های از جنس کد درون رشته استفاده کنیم.

داشتن دانش درباره استفاده از این روش‌ها باعث ارتقای مهارت‌های مربوط به کار با داده‌ها می‌شود. در نتیجه می‌توانیم رشته‌ها را با انعطاف‌پذیری و کارآمدتری بیشتری مدیریت و پردازش کنیم.

source

توسط expressjs.ir