لگو بازی با گنو/لینوکس: تلفظ کامل یک جمله
توسط: vahit
سلام
خب تقریباً یک ماه پیش بود که پست «لگو بازی با گنو/لینوکس: تلفظ لغات در NOKIA N900.» رو ارسال کردم و یاد گرفتیم که چطور این کار رو انجام بدیم. ولی خب یه چند تا راه برای گسترش و بهتر کردنش وجود داره و توی این پست می خوایم اینا رو بررسی کنیم.
اوّلین مورد: اگر به یاد داشته باشید در پست قبل گفتم که:
خب تا اینجا هدف ما برآورده شد ولی یه خورده بهتر ترش می کنم. مثلاً اگر تلفظی وجود نداشت می خوام این مسئله رو با من در میون بزاره. برای این کار از دستور if استفاده می کنم تا به طور مستقیم وجود فایل رو بررسی کنه اگر وجود داشت پخش بشه و اگر وجود نداشت یه متن ساده که حاکی از وجود نداشتن فایل تلفظ برای کلمه ی مورد نظر هست رو نشون بده.
خب حالا نظرم عوض شده (اگر اشتباه نکنم این مورد رو شاهین توی یه گفتگوی اینترنتی برام یادآوری کرد. ممنون ازش :) ) و می خوام اگر فایل تلفظی برای کلمه ای وجود نداشت espeak اون رو تلفظ کنه پس فقط کافیه قسمت else دستور if رو تغییر بدم و به جای چاپ متن دستور espeak رو با ورودی همون کلمه (آرگومان) بنویسم. پس فقط همون خط رو عوض می کنم و اسکریپت به این شکل میشه:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/bash declare DIR DIR=`echo $2 | cut -c1` if test -f /home/user/MyDocs/others/.WyabdcRealPeopleTTS/$DIR/$2.wav; then for ((count=1; count<=$1; count++)); do printf "%s$count " aplay /home/user/MyDocs/others/.WyabdcRealPeopleTTS/$DIR/$2.wav 2> /dev/null sleep 1 done printf ".\n" else espeak ${args[$i]} &> /dev/null fi exit 0 |
خب تا این جا به جز یه مورد همه چی خوبه, اون یه مورد هم این هست که من چرا آخر دستور نوشتم
1 |
&> /dev/null |
دستور espeak هنگام کار خروجی هایی داره (error/output) که برای ما لازم نیستن و فقط ترمینال رو شلوغ می کنن و من با اضافه کردن این دستور خواستم همه ی standard streams رو یک جا به فایل
1 |
/dev/null |
ارسال کردم. برای اینکه با standard streams آشنا بشین می تونید به اینجا و اینجا مراجعه کنید.
دوّمین مورد:این مورد هم با دیدن نظر شاهین در پست قبل (که در بالا لینک دادم) به ذهنم رسید. (یعنی اوّلش فکر کردم منظورش این هست ولی بعداً باهاش صحبت کردم و دیدم این نبود:D ) یعنی بتونیم کل یه جمله رو تلفظ کنیم. کار سختی نیست ما که هر کلمه ای رو تونستیم با آخرین آپدیت (اسکریپت بالا) تلفظ کنیم هر جمله هم از تعدادی کلمه تشکیل شده که بینشون یک فاصله قرار گرفته پس فقط کافیه کلمات یک جمله رو هم یکی یکی و پشت سر هم تلفظ کنیم. تنها مشکل سر راهمون این هست که بتونیم کلمات یک جمله رو بدست بیاریم، لابد الان تو فکرتون هست که یه برنامه بنویسم و که همه ی کاراکترهای ورودی رو بررسی کنه تا اگر فاصله (space) بود اون رو به سبب بک کلمه بودن جدا کنه!! من می گم این کار لازم نیست خوبی شل اسکریپت هم اینه که اگر کل جمله رو از ورودی به اسکریپت بدیم هر کلمه یک آرگومان حساب میشه (البته دلیل اصلیش IFS هست!!) یعنی جدا از بقیه. و خب من می تونم تمامی آرگومان ها رو توی یک آرایه ذخیره کنم و یکی یکی تلفظشون کنم. (البته من همین اسکریپت رو تغییر میدم.) برای ایجاد آرایه مثل تعریف متغیرها عمل می کنیم با این تفاوت که آپشن a رو به دستور declare اضافه می کنیم تا متوجه بشه که این متغیر یه آرایه هست.
1 |
declare -a args; |
خب میدونیم که عبارت
1 |
$@ |
به همه ی آرگومان ها اشاره می کنه پس من اگر آرایه ای رو که تعریف کردم به شکل زیر مقدار دهی کنم هر آرگومان داخل یکی از خانه های آرایه قرار می گیره (و دنبال کردن خانه های آرایه به راحتی با حلقه امکان پذیره):
1 |
args=("$@"); |
گفتیم حلقه! می خوام از حلقه ی for استفاده کنم که شمارندش از ۱ شروع می شه و تا… و تا … راستی حلقه تا کجا باید ادامه پیدا کنه؟ خب می دونیم که تعداد کلمات جمله ثابت نیست و این رو می دونیم که همه ی کلمات داخل آرایه قرار گرفتن پس میشه طول آرایه رو بررسی کرد یا مثلاً چون گفتنم هر کلمه یک آرگومان حساب شده پس تعداد آرگومانها همون تعداد کلمات خواهد بود. آره این راححتره. تعداد آرگومان رو همیشه می شه از طریق مقدار
1 |
$# |
فهمید. پس حلقه اینجوری تشکیل میشه
1 2 3 |
for (( i=0; i < $#; i++)); do ### commands done |
خب چون گفته بودیم می خوایم هر کلمه از جمله رو جدا گانه تلفظ کنیم کافیه به جای commands داخل حلقه قسمت تلفظ کننده ی اسکریپت بالا رو اضافه کنیم. در نهایت اسکریپت چیزی شبیه به این میشه (البته مستقل از قبلی ):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#!/bin/bash declare -i i; declare -a args; declare DIR; args=("$@"); for (( i=0; i < $#; i++)); do DIR=`echo ${args[$i]} | cut -c1`; if test -f /home/wahid/WyabdcRealPeopleTTS/$DIR/${args[$i]}.wav; then aplay /home/wahid/WyabdcRealPeopleTTS/$DIR/${args[$i]}.wav 2> /dev/null else espeak ${args[$i]} &> /dev/null; fi done exit 0 |
اجراش می کنیم و به به . موقع امتحان جملات و لذت بردن از دستاوردمون Oooops! یه مشکل! وقتی کلمه ای رو با یک با بیشتر حرف بزرگ تایپ می کنیم کلمه از طریق espeak تلفظ می شه! مشکل اینجاست که یادمون رفته بود که گنو/لینوکس case sensitive هست. یعنی اینکه به حروف کوچک و بزرگ حساس هست یعنی براش hello با Hello و … فرق داره! یعنی باید کل جمله رو با حروف کوچک بنویسیم ولی خیلی بده کاربر رو محدود کنیم و بهش بگین این کارو بکن یا نکن ناسلامتی داریم از آزادی حرف می زنیم!! پس باید بزاریم کاربر جلو ترمینال وقتی داری با اسکریپت کار می کنه جولان بده و ما خودمون ورودی رو به شکل درست تبدیل کنیم. پس یه صورت مسئله ی جدید می نویسیم: «چطوری ورودی رو به حروف کوچک تبدیل کنیم؟» جوابش سخت نیست، یه دستوری داریم به اسم tr که می تونه کار مورد نظر ما رو انجام بده. (یه نگاهی به man اش بندازین!) شکلش به این صورت هست:
1 |
tr '[:upper:]' '[:lower:]' |
یعنی همه ی کاراکتر های حروف بزرگ ورودیت رو به حرف کوچک تبدیل کن. طبیعی هم هست که با حروف کوچک کاری نخواهد داشت. خب ورودی ما هم همون کلمات هست پس من خط ششم رو به شکل زیر تغییر میدم:
1 |
args=(`echo $@ | tr '[:upper:]' '[:lower:]'`); |
فکر میکنم به اندازه ی کافی گویا باشه تا نیازی به توضیح نداشته باشه.
پس اسکریپت در نهایت به شکل زیر میشه:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/bash declare -i i; declare -a args; declare DIR; args=(`echo $@ | tr '[:upper:]' '[:lower:]'`); for (( i=0; i < $#; i++)); do DIR=`echo ${args[$i]} | cut -c1`; if test -f /home/wahid/WyabdcRealPeopleTTS/$DIR/${args[$i]}.wav; then aplay /home/wahid/WyabdcRealPeopleTTS/$DIR/${args[$i]}.wav 2> /dev/null else espeak ${args[$i]} &> /dev/null; fi done exit 0 |
پی نوشت: از لحاظ فنی شاید نتیجه این اسکریپت خیلی بی روح باشه ولی هدف فقط انجام یه تصمیم و یادگیری چیزهای جالب و جدید در این راه بود.
خیلی خوب بود، خوشمان آمد.
دیدم کسی نظر نداده گفتم برای دل گرمی هم که شده نظر بدم.
ولی جدا از شوخی مطالبت خوبه،
منم مشتاق ان 900 شدم!
ممنون :) لطف داری دوست عزیز.
حالا وقت نمی شه پست های اصلی رو در مورد N900 بزنم وگرنه محشره این گوشی. :)
ما منتظر پستهای جدید هستیم! :)
به زودی :)
[…] لگو بازی با گنو/لینوکس: تلفظ کامل یک جمله […]