|
انجام عملیات بر روی
رشته ها در بسیاری از پروژه ها لازم می شود. هر برنامه نویسی باید در
انجام این عملیات راحت باشد، لذا لیستی از توابع پرکاربرد را در Visual
Basic 6 به صورت فهرست وار بررسی می کنیم
و سپس مساله ای را به کمک این توابع و روش تقسیم و حل، حل خواهیم کرد.
Function Len ( Expression As String ) As Long
تابع بالا رشته Expression را گرفته و طولش (تعداد کاراکترهایش) را بر می گرداند. تابعی دیگری با نام LenB وجود دارد که طول رشته را بر حسب بایت بر می گرداند.
Function Left ( Str As String, Length As Long ) As String
این تابع به تعداد مشخص شده - توسط Length - کاراکتر را از سمت چپ بر می گرداند.
Function Right ( Str As String, Length As Long ) As String
این تابع به تعداد مشخص شده - توسط Length - کاراکتر را از سمت راست بر می گرداند.
Function InStr ( String1 As String, String2 As String ) As Long
محل
رشته String2 را در رشته String1 از طرف چپ مشخص می کند. به یاد داشته
باشید، که در ویژوال بیسیک 6 بر خلاف زبان هایی مانند Java و ++C شمارش
رشته از 1 شروع می شود نه صفر.
Function UCase ( Str As String ) As String
حروف کوچک Str را به حروف بزرگ تبدیل می کند. در ضمن تابع LCase عکس این تابع عمل می کند.
Function Asc ( Str As String ) As Integer
تابع بالا کد اسکی (ASCII) اولین کاراکتر رشته Str را بر می گرداند. تابع ChrB عکس این عمل را انجام خواهد داد.
Function IsNumeric ( Str As String ) As Boolean
بررسی می کند آیا رشته ورودی یک عدد است یا خیر.
Function Str ( Num As String ) As String
عدد ورودی را تبدیل به رشته معادلش در میدان رشته ها می کند.
Function Val ( Str As String ) As Double
اعداد درون رشته Str را تحویل می دهد.
بررسی
تمام این تابع ها در این مقاله می تواند کسل کننده باشد. می توانید با
فشردن کلید F2 در محیط VB6 همه توابع کتابخانه ای و دیگر
اجزای آنرا ببینید.
حال
به مساله کلاسیک زیر توجه کنید. هدف از طرح این مساله آشنایی با مدیریت
رشته ها و نیز پی به بردن به کارایی و شیوایی روش بازگشتی در حل برخی از
مسائل است، که تعدادشان کم هم نیست!
مساله:
رشته
ای مانند " ۱۲ * (۳ + ۴) - ۲ / ۱" که ترکیبی با معنی از عملگرها و
عملوندها است را در اختیار داریم. می خواهیم روشی پیدا کنیم که بتوانیم
حاصل رشته هایی این چنین را پیدا کنیم. برنامه باید بتواند بین
رشته های "۳ * (۴ + ۲)" و "۳ * ۴ + ۲" و نیز بین رشته های "۱ + ۲ - ۳" و
"(۱ + ۲) - ۳" تفاوت قائل شود. به عبارت بهتر باید بتوانیم تقدم عملگرها
را پیاده سازی کنیم.
تقدم عملگرها در Visual Basic 6 همانند اکثر زبان ها این چنین است (از بالا به پایین):
|
پرانتزها
|
( )
|
|
عملگر توان
|
^
|
|
تفریق یکانی مثلا در: (۳+۱)-
|
-
|
|
تقسیم و ضرب معمولی
|
/ و *
|
|
تفریق و جمع معمولی
|
- و +
|
عملگرهای
بالاتر جدول فوق در یک عبارت زودتر اجرا می شوند، اما در مورد عملگرهایی
که در یک سطر هستند، هر کدام زودتر ظاهر شود (از طرف چپ) تقدم با اوست. این مساله را در ادامه با روش باز گشتی حل می کنیم.
با ارائه مثالهایی از روند اجرای کار، الگوریتم را برای شما تشریح می کنم. فرض
کنید رشته "۵ + ۱۰ * ۲.۳" را دریافت کرده ایم و می خواهیم از روش تقسیم و
حل جواب آن را پیدا کنیم. باید رشته مذکور را به دو بخش تجزیه کرده و هر
قطعه را دوباره تحویل تابع دهیم.
اگر نمی خواستیم تقدم عملگرها رعایت شود کار ساده بود. از ابتدای رشته شروع می کردیم و هر
کجا به عملگر می رسیدیم رشته را به دو زیر رشته تقسیم کرده و هر کدام را
دوباره به تابع تحویل می دادیم، تا آنجا که به یک عملوند تنها برسیم. برای
مثال در این حالت که تقدم مهم نیست، رشته بالا را این چنین تقسیم می کنیم
(در اینجا معیار اولین تقسیم به زیر رشته ها ضرب است):

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

در حالت اول تجزیه نادرست از آب در آمد، چرا؟ چون تقدم ضرب بیشتر از جمع است.
با مقایسه تصاویر بالا و مطالب گفته شده به نتیجه مهم زیر می رسیم:
نتیجه ۱: در
تجزیه رشته ها به رشته های کوچکتر معیار تقسیم (به معنای معیار تقسیم در
مثال های بالا توجه کنید) باید در حد توان، تقدم کمتری داشته باشد.
برای مثال در بالا که دو عملگر * و + داریم یا باید بر اساس عملگر ضرب تقسیم کنیم یا بر اساس عملگر جمع. نتیجه
1 می گوید که برای حفظ تقدم ضرب، برنامه باید رشته را بر اساس عملگر + به
دو زیر مساله تجزیه کند. در نتیجه رشته بالا به دو رشته "5" و "10 * 2.3"
تجزیه خواهد شد.
ولی ممکن است عملگری که تقدم کمتری دارد درون پرانتز باشد، مانند "۴ * (۳+۲)". در
این حالت بالاخره کل عبارت پرانتز دارای حاصلی است ، و ما فرض می کنیم که
به جای این عبارت حاصلش نشسته است. نتیجه این فرض این است که به عملگرهای
درون پرانتز توجه نمی شود، یعنی مثلا در رشته بالا معیار اولین تقسیم به
زیر رشته ها عملگر ضرب است نه جمع، چون "+" درون پرانتز ظاهر شده. پس
نتیجه ۱ را بهبود بخشیده و می نویسیم:
نتیجه ۱ اصلاح شده: در تجزیه رشته ها به رشته های کوچکتر معیار تقسیم باید در حد امکان تقدم کمتری داشته و درون پرانتز نباشد.
حالت
دیگری که ممکن است اتفاق بیفتد این است که با رشته ای نظیر "۲۰ + ۳ - ۲"
روبرو شویم، رشته ای که دو عملگر هم تقدم هستند. این رشته هم مانند
بالایی به دو صورت متفاوت تجزیه می شود. ولی کدام تجزیه صحیح است؟ در
اینجا چون "-" زودتر آمده است تقدم با اوست، پس "+" تقدم کمتری دارد و طبق
نتیجه ۱ باید معیار تجزیه اول "+" باشد، چون دیرتر آمده و این یعنی:
نتیجه ۲: جستجوی عملگر برای یافتن معیار تقسیم را درون رشته از انتهای آن آغاز می کنیم.
اگر
دقت کرده باشیم بر روی "اولین تقسیم" تاکید خاصی داریم. دلیلش این است که
الگوریتم ما بازگشتی است، و ماهیت تجزیه چنین رشته هایی بازگشتی می باشد.
و عمل تجزیه یک بار پیاده سازی می شود.
حال شروع به نوشتن کدها می کنیم:
در ابتدا رشته را از انتها تا به ابتدا بررسی می کنیم، تا موقعیت تک تک عملگرهای "+" ، "-" ، "*" ، "/" ، "^" را
بیابیم. برای این منظور تابع زیر را می نویسیم که رشته و عملگر و طول رشته
را گرفته و موقعیت آن را با شرایط زیر برگرداند :
Function Location ( ByVal pStr As String, ByVal Op As String, ByVal n As Integer ) As Long
Dim Cp As Long
Dim Ch As String
Cp = 0
Location = 0
For i = n To 1 Step -1
Ch = CharAt ( pStr, i )
Select Case Ch
Case ")"
Cp = Cp + 1
Case "("
Cp = Cp - 1
Case Op
If Cp = 0 Then
Location = i
Exit For
End If
End Select
Next i
End Function
کد
به اندازه کافی واضح است. فقط این که در بالا از تابع CharAt استفاده شده
است که i امین (... ،۳ ،۲ ،۱ = i) کاراکتر رشته pStr را بر می گرداند.
نوشتن آن ساده است و آن را به عنوان تمرین به عهده شما می گذارم.
حال
تابع اصلی برنامه را می نویسیم، این تابع برای تجزیه رشته از تابع
Location کمک خواهد گرفت. تجزیه وقتی متوقف می شود که به یک عدد برسیم.
لازم است ذکر شود بعد از این که رشته به تابع ارسال شد باید بررسی شود که آیا دارای پرانتز اضافی دور خودش
است یا نه و در صورت وجود، آن پرانتزها باید حذف شوند، برای مثال رشته های
"(۱ + ۳)" و "((۲ + ۱.۵) * ۳)" چنین خصوصیتی دارند، ولی رشته "(۳ + ۱) +
((۸ + ۱۰))" چنین خاصیتی ندارد. برای این که بتوانیم درون رشته کنکاش کنیم
چنین عملی واجب است. عمل بالا را به عهده روال RemoveBracket می گذاریم.
این هم تابع اصلی:
Public Function Value ( ByVal pStr As String ) As Double
Dim jam, tafrig, zarb, tagsim, tavan, Lstr As Integer
Dim str1, str2 As String
pStr = RemoveBracket ( pStr )
Lstr = Len ( pStr )
jam = Location ( pStr, "+", Lstr )
tafrig = Location ( pStr, "-", Lstr )
zarb = Location ( pStr, "*", Lstr )
tagsim = Location ( pStr, "/", Lstr )
tavan = Location ( pStr, "^", Lstr )
If jam > 0 And ( tafrig = 0 Or jam > tafrig ) Then
str1 = Left ( pStr, jam - 1 )
str2 = Right ( pStr, Lstr - jam )
Value = Value ( str1 ) + Value ( str2 )
ElseIf tafrig > 0 Then
str1 = Left ( pStr, tafrig - 1 )
str2 = Right ( pStr, Lstr - tafrig )
If str1 = Empty Then
Value = -Value ( str2 )
Else
Value = Value ( str1 ) - Value ( str2 )
End If
ElseIf zarb > 0 And ( tagsim = 0 Or zarb > tagsim ) Then
str1 = Left ( pStr, zarb - 1 )
str2 = Right ( pStr, Lstr - zarb )
Value = Value ( str1 ) * Value ( str2 )
ElseIf tagsim > 0 Then
str1 = Left ( pStr, tagsim - 1 )
str2 = Right ( pStr, Lstr - tagsim )
v2 = Value ( str2 )
Value = Value ( str1 ) / v2
ElseIf tavan > 0 Then
str1 = Left ( pStr, tavan - 1 )
str2 = Right ( pStr, Lstr - tavan )
Value = Value ( str1 ) ^ Value ( str2 )
ElseIf IsNumeric ( pStr ) Then
Value = Val ( pStr )
End If
End Function
همانطور
که عنوان شد و مشاهده می کنید تابع فوق از تابعی به نام RemoveBracket
استفاده می کند که پرانتزهای اضافی عبارت را حذف می کند. نوشتن کد این
تابع را به عنوان تمرین به خوانندگان عزیز واگذار می کتیم!
شاید
تا کنون متوجه شده باشید: برنامه بالا از این نظر که هیچ کنترلی بر خطاهای
زمان اجرا ندارد ناقص است. شما می توانید این کار را خودتان انجام دهید.
یعنی برای مثال اگر کاربر رشته های "۴ + + ۱" یا "۰ / ۱" یا "(۳ + ۱))"
را وارد کند، برنامه قادر به مدیریت آن ها باشد و خارج نشود. همچنین می
توانید برنامه را گسترش داده و توابع ریاضی مانند Sin و Cos را در برنامه
بگنجانید. در این حالت برنامه باید قادر به محاسبه "Sin(2 + 1) + 1" باشد.
منبع:Aachp.ir
|