PDA

View Full Version : جايگزيني زير رشته



pazahr
یک شنبه 02 فروردین 1388, 11:26 صبح
procedure FileReplaceString(const FileName, searchstring, replacestring: string);
var
fs: TFileStream;
S: string;
begin
fs := TFileStream.Create(FileName, fmOpenread or fmShareDenyNone);
try
SetLength(S, fs.Size);
fs.ReadBuffer(S[1], fs.Size);
finally
fs.Free;
end;
S := StringReplace(S, SearchString, replaceString, [rfReplaceAll, rfIgnoreCase]);
fs := TFileStream.Create(FileName, fmCreate);
try
fs.WriteBuffer(S[1], Length(S));
finally
fs.Free;
end;
end;

كد بالا رو ببينيد
تست كردم با پارامترها و متغيرهاي متناسب با خودم بدون اينكه خطا بده اجرا ميشه اما زيررشته اي كه مي خوام تغيير كنه تغيير نمي كنه! شما تستش كرديد؟ نكته خاصي داره؟
من filename و searchstring و replacestring رو عوض كردم.

vcldeveloper
چهارشنبه 05 فروردین 1388, 04:13 صبح
در چه نسخه ایی از دلفی؟
لزومی نداشت یک بار فایل را با TFileStream باز کنید. می تونید مستقیما فایل را با استفاده از متد LoadFromFile مربوط به TStringStream در Stream بریزید، و رشته را با استفاده از خصوصیت DataString آن بدست بیارید، تغییرات مورد نظر را روی آن انجام بدید، و با SaveToFile در فایل ذخیره کنید.

vcldeveloper
جمعه 07 فروردین 1388, 10:09 صبح
pazahr (http://barnamenevis.org/forum/member.php?u=13625)،
قرار نیست هر کس اینجا به جواب رسید، تاپیک خودش را حذف کنه! تاپیک از حالت حذف خارج شد. اگر به حذف تاپیک های خودتان که به جواب رسیدند ادامه بدید، جریمه میشید!

pazahr
جمعه 07 فروردین 1388, 11:03 صبح
بعد از اينكه روي همين كد كار كردم دو اشكال اون رو به اين شكل حل كردم :

1 - خط اول filename بايد به شكل متغير استفاده بشه نه const
2 - توي برنامه اصلي بايد اين تابع نوشته شده رو فراخواني كرد و پارامتر واقعي نشون دهنده رشته يعني S بجاي string بايد widestring تعريف بشه. فايلي كه من باز مي كردم يخورده حجمش بالا بود و string كم مي آورد! كه اگر widestring بشه مشكل دقيقا حل ميشه.
ممنون از راهنماييتون.

vcldeveloper
جمعه 07 فروردین 1388, 11:27 صبح
- خط اول filename بايد به شكل متغير استفاده بشه نه const
2 - توي برنامه اصلي بايد اين تابع نوشته شده رو فراخواني كرد و پارامتر واقعي نشون دهنده رشته يعني S بجاي string بايد widestring تعريف بشه. فايلي كه من باز مي كردم يخورده حجمش بالا بود و string كم مي آورد! كه اگر widestring بشه مشكل دقيقا حل ميشه.مشکل از این چیزهایی که مطرح کردید نبوده چون:
1- FileName باید بصورت const تعریف میشد تا کارایی کد افزایش پیدا کنه. اگر از const استفاده نشه، کامپایلر یک بلوک try-finally مخفی در داخل کد تابع ایجاد میکنه. در این زمینه در یک تاپیک دیگه توضیح دادم، نمونه کدهای اسمبلی تولید شده در صورت استفاده از const و استفاده نکردن از آن را هم گذاشتم.

2- حجم فایل شما ربطی به string و widestring نداره. string محدودیت خاصی در حجم داده ذخیره شده نداره. تنها محدودیتی که میشه برای string در نظر گرفت، محدودیتی هست که سیستم عامل بر روی پروسه ها اعمال میکنه و به هر پروسه 4 گیگابایت فضای مجازی اختصاص میده. از آنجایی که 2 تا حداکثر 3 گیگابایت از این فضا قابل دسترس از User Mode هست، و مابقی توسط کرنل سیستم عامل استفاده میشه، string شما میتونه نزدیک به 2 (یا اگر گزینه مربوطه در ویندوز فعال شده باشه، 3 گیگابایت) حجم داشته باشه. البته به شرطی که سیستم شما منابع لازم برای همچین حجمی از داده را داشته باشه.
استفاده از WideString بجای string ربطی به حجم داده ذخیره شده نداره. WideString در نسخه های قدیمی دلفی (قبل از دلفی 2009) برای نگهداری رشته های یونیکد استفاده میشه، و هر کارکتر آن دو برابر string فضا اشغال میکنه. از نظر کارایی هم کارایی ضعیف تری از string داره. پس، در صورتی جایگزینی string با WideString منطقی بود که؛ اولا شما از نسخه ایی غیر از دلفی 2009 استفاده بکنید، و ثانیا نوع داده هایی که میخواید نگهداری کنید یونیکد باشه.

در هر حال، هیچکدوم از مواردی که به عنوان راه حل مطرح کردید، درست نبودند.

pazahr
جمعه 07 فروردین 1388, 11:44 صبح
1 - موقعي كه با const خواستم كامپايل كنم خطا مي گرفت و بعد از تبديل شيوه عمل از ثابت به متغير مشكل اين قسمت حل شد
2 - من از دلفي هفت استفاده مي كنم. وقتي اين تابع رو با نوع string فراخواني مي كرد واقعا خسته ام كرد! چون خيلي بد قلقي مي كرد! يعني فايل متني رو عوض مي كردم كه مي خواستم به ازاي موارد مختلف خوب تستش كنم يه بار جواب مي داد و يه بار جواب نمي داد (بگير نگير) تا اينكه بيشتر متمركز شدم به كد و متوجه شدم كه به كمك filestram كل متن موجود در فايل توي يه متغير به نام S قرار داده ميشه و بعد بجاي جستجو در فايل توي اين متغير رشته اي جستجو و جايگزيني انجام ميشه و دوباره فايل ساخته يا overwrite ميشه. پس اگر حجم فايل بالا باشه قاعدتا با توجه به محدوديت string كم مي آورد كه سريع نوع آن رو widestring تعريف كردم و دقيقا جواب گرفتم.
نمي دونم. توضيحات شما احتمالا در مورد دلفي 2009 صادق هست.

vcldeveloper
جمعه 07 فروردین 1388, 21:12 عصر
1 - موقعي كه با const خواستم كامپايل كنم خطا مي گرفت و بعد از تبديل شيوه عمل از ثابت به متغير مشكل اين قسمت حل شدمتن خطا را ننوشتید. به احتمال خیلی زیاد در کد سعی کردید مقدار FileName را تغییر بدید، که با توجه به تعریف آن بصورت const، کامپایلر مانع این کار شد.


2 - من از دلفي هفت استفاده مي كنم. وقتي اين تابع رو با نوع string فراخواني مي كرد واقعا خسته ام كرد! چون خيلي بد قلقي مي كرد! يعني فايل متني رو عوض مي كردم كه مي خواستم به ازاي موارد مختلف خوب تستش كنم يه بار جواب مي داد و يه بار جواب نمي داد (بگير نگير) تا اينكه بيشتر متمركز شدم به كد و متوجه شدم كه به كمك filestram كل متن موجود در فايل توي يه متغير به نام S قرار داده ميشه و بعد بجاي جستجو در فايل توي اين متغير رشته اي جستجو و جايگزيني انجام ميشه و دوباره فايل ساخته يا overwrite ميشه. پس اگر حجم فايل بالا باشه قاعدتا با توجه به محدوديت string كم مي آورد كه سريع نوع آن رو widestring تعريف كردم و دقيقا جواب گرفتم.
نمي دونم. توضيحات شما احتمالا در مورد دلفي 2009 صادق هست. خیر، مطلبی که من مطرح کردم از دلفی 2 تا آخرین نسخه دلفی (یعنی دلفی 2009) صادق هست. نوع داده string در دلفی محدودیتی جز منابع سیستم که توسط سیستم عامل در اختیار پروسه قرار داده میشه، نداره. پیش فرض شما کاملا اشتباه هست. اگر به راهنمای دلفی مراجعه می کردید، متوجه می شدید که نوع داده WideString هیچ مزیتی از نظر حجم داده قابل ذخیره سازی نسبت به string ندارد.
اگر مشکل کد شما به نوعی حل شده، احتمالا در کد نوشته شده، یا در محاسبه حجم داده ها اشتباهاتی داشتید که استفاده از WideString باعث شده بطور اتفاقی اشتباهات مورد نظر برطرف بشند، چون هر کارکتر در WideString دو بایت، و در string یک بایت اشغال میکنه. به عنوان مثال، اگر برای s در کد زیر از WideString استفاده بشه:


fs.WriteBuffer(S[1], Length(S)); اگر فرض بگیریم عبارتی مثل "Test" در فایل ذخیره شده باشه، مقدار Length(S) = 4 خواهد بود، ولی حجم رشته 8 بایت خواهد بود. WriteBuffer با حجم بایت کار داره، نه با تعداد کارکترها، پس به فرض اگر S بصورت WideString تعریف شده باشه، کد بالا فقط باعث انتقال نصف رشته به stream میشه، و برای انتقال کامل رشته به stream باید نوشته میشد:

fs.WriteBuffer(S[1], Length(S) * SizeOf(WideChar)); اگر کد شما با همون مقادیر غلطی که بهش میدید، درست عمل میکنه، پس جایی در محاسبات کد اشتباه کردید، که بطور اتفاقی این اشتباه آن اشتباه را برطرف میکنه.