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


دیروز به من اطلاع دادند که در یکی از برنامه‌ها دو تا گروه "تاسیسات مکانیکی" پیدا شده!!
تاسیسات مکانیکی
تاسیسات مکانیکی

استاندارد این شرکت، استفاده از kbdfa.dll مخصوص و نسبتا قدیمی است. بنابراین استاندارد مورد استفاده همان ی و ک عربی است. (کاری ندارم خوب است یا بد، یا باید اینطور باشد یا نه، بحث این است که فعلا اینطور است و قرار نیست چیزی عوض بشود!)
در مثال فوق، ی و ک عبارت دوم فارسی است. یعنی نصب kbdfa.dll روی ویندوز تازه نصب شده، فراموش شده بوده.

راه حل‌ها:
الف) قبل از ثبت، یکسان سازی صورت گیرد. یعنی اجرای متدی شبیه به متد زیر بر روی هر ورودی متنی فارسی:

public string SafeFarsiStr(string input)
{
return input.Replace("ی", "ی").Replace("ک", "ک");
}

ب) خوب، الان که این یکسان سازی صورت نگرفته چه باید کرد؟
اسکریپتی را تهیه کرده‌ام (مخصوص SQL Server 2005 به بعد) به صورت زیر که این تبدیل را برای شما انجام می‌دهد.
به صورت خودکار تمامی فیلدهای متنی کلیه جداول دیتابیس جاری شما را یافته و ی و ک آن‌ها را یکسان می‌کند. البته همانطور که عرض شد، مطابق استاندارد این شرکت و استفاده از فایل kbdfa.dll قدیمی مورد استفاده، تمام ی و ک های فارسی به عربی تبدیل می‌شوند.

--اسکریپتی برای یک دست سازی ی و ک در تمامی رکوردهای تمامی جداول دیتابیس جاری
-- اسکریپت زیر ی و ک فارسی را به عربی تبدیل می‌کند
-- در صورت نیاز به حالت عکس ، جای مقادیر عددی یونیکد را تعویض نمائید

USE TestDb;

DECLARE @Table NVARCHAR(MAX),
@Col NVARCHAR(MAX)

DECLARE Table_Cursor CURSOR
FOR
--پیدا کردن تمام فیلدهای متنی تمام جداول دیتابیس جاری
SELECT a.name, --table
b.name --col
FROM sysobjects a,
syscolumns b
WHERE a.id = b.id
AND a.xtype = 'u' --User table
AND (
b.xtype = 99 --ntext
OR b.xtype = 35 -- text
OR b.xtype = 231 --nvarchar
OR b.xtype = 167 --varchar
OR b.xtype = 175 --char
OR b.xtype = 239 --nchar
)

OPEN Table_Cursor FETCH NEXT FROM Table_Cursor INTO @Table,@Col
WHILE (@@FETCH_STATUS = 0)
BEGIN
EXEC (
'update [' + @Table + '] set [' + @Col +
']= REPLACE(REPLACE(CAST([' + @Col +
'] as nvarchar(max)) , NCHAR(1740), NCHAR(1610)),NCHAR(1705),NCHAR(1603)) '
)

FETCH NEXT FROM Table_Cursor INTO @Table,@Col
END CLOSE Table_Cursor DEALLOCATE Table_Cursor

توضیحات و نکاتی در مورد اسکریپت فوق:
الف) برای آشنایی با انواع XType Datatype مورد استفاده در کوئری فوق به این آدرس مراجعه نمائید.
ب) همانطور که در مطالب قبلی این وبلاگ نیز ذکر شد، امکان استفاده از تابع replace بر روی فیلدهای text و ntext وجود ندارد. هیچ اشکالی ندارد! تمام آن‌ها به nvarchar از نوع max دار cast شده و این مشکل به این صورت حل می‌شود.
ج) اس کیوال سرور اجازه تعریف یک جدول یا فیلد را به صورت متغیر بکار رفته در یک کوئری T-SQL نمی‌دهد. برای حل این موضوع باید عبارت SQL مورد نظر را به صورت یک رشته درآورد و سپس exec کرد.
د) مجبور شدم از معاد‌ل‌های عددی برای دقت بیشتر کار استفاده کنم



(در کل از تابع UNICODE اس کیوال سرور برای بدست آوردن این اعداد می‌توان استفاده کرد)

تذکر: این اسکریپت بر روی یک دیتابیس کاری تست شده و نتیجه رضایت بخش بوده؛ اما اگر شما روزی خواستید از آن استفاده کنید، حتما full backup را قبل از اجرای آن فراموش نکنید و پس از اجرا، تابع SafeFarsiStr فوق را برای ادامه کار حتما لحاظ نمائید یا از یک kbdfa.dll هماهنگ استفاده کنید.


  • #
    ‫۱۵ سال و ۹ ماه قبل، چهارشنبه ۲۵ دی ۱۳۸۷، ساعت ۱۱:۲۲
    خیلی به درد بخور بود.
  • #
    ‫۱۵ سال و ۹ ماه قبل، چهارشنبه ۲۵ دی ۱۳۸۷، ساعت ۱۱:۴۵
    بعضی نسخه‌های kbdfa.dll بر اساس استاندارد ۲۹۰۱ هستند. استاندارد ۲۹۰۱ توسط استاندارد جدیدتر ۹۱۴۷ باطل اعلام گردید. البته اختلاف این دو تا استاندارد خیلی توی چشم نمی‌زند.
    یک درایور خوب هم برای استاندارد ۹۱۴۷ وجود دارد که من در ویندوز ویستا و چندین ویندوز ایکس پی از آن استفاده می‌کنم بدون این که مشکلی برایم به وجود آمده باشد.

    آدرس درایور: http://prdownloads.sourceforge.net/farsitools/persiankeyboard.zip?download

    مطالعه استاندارد: http://fa.farsiweb.ir/mediawiki-fa/images/a/a9/Isiri-9147.pdf

    لینک استاندارد در سایت سازمان استاندارد: http://www.isiri.org/asp/account/checklog.asp?ID=9147.pdf


    بیاید از زبان فارسی حمایت کنیم.
  • #
    ‫۱۵ سال و ۹ ماه قبل، پنجشنبه ۲۶ دی ۱۳۸۷، ساعت ۱۸:۰۶
    مطلب خوبی بود اما من هم با افشار موافقم که باید از فارسی حمایت کرد و بهتره که بجای جایگزینی حروف فارسی با عربی ، بهتره که از فونتهای استاندارد استفاده بشه و حروف عربی به فارسی تبدیل بشن
    -
    از مطلب خوبتون هم واقعا ممنونم
  • #
    ‫۱۵ سال و ۹ ماه قبل، پنجشنبه ۲۶ دی ۱۳۸۷، ساعت ۱۹:۳۴
    اگر این مورد به نحوی در خود برنامه‌های پایگاه داده حل بشود، این مسایل دیگر وجود نخواهد داشت.
    مثلا اس کیوال سرور ی و ى را به یک صورت پردازش کند و جدا از هم درنظر نگیرد.
    این مورد الان در جستجوی گوگل هم مشهود است و مشکل زا. شما با ی یک سری جواب می‌گیرید و با ى یک سری دیگر. این مورد مهم است!
  • #
    ‫۱۵ سال و ۹ ماه قبل، دوشنبه ۷ بهمن ۱۳۸۷، ساعت ۲۰:۲۸
    تو برنامه تون (دات نتی) با استفاده از MessageFilter می تونید کلیه ورودی ها رو تحت کنترل داشته باشید.
  • #
    ‫۱۴ سال و ۲ ماه قبل، چهارشنبه ۲۷ مرداد ۱۳۸۹، ساعت ۰۴:۴۷
    مرسی از کمکت عالی بود...
  • #
    ‫۱۳ سال و ۱۲ ماه قبل، پنجشنبه ۲۹ مهر ۱۳۸۹، ساعت ۱۸:۲۳
    با سلام و تشکر از مطالب مفیدتون.
    استاندارد سیستم من فارسی هست و میخوام همون هم ذخیره بشه.
    من این اسکریپت رو اجرا کردم (البته با تغییر در replace و جابه جا کردن فارسی و عربی) و دیتابیس رو درست کرد.
    فقط الان یه مشکلی دارم(البته فکر می کنم قبل از این اسکریپت هم بوده): هر insert که می زنم ، خود SQL "ی" فارسی رو به "ی" عربی تبدیل می کنه و ذخیره می کنه. یعنی من 1740 می فرستم ولی 1610 ذخیره میشه. این مشکل در مورد ک وجود نداره و همون 1705 فرستاده و ذخیره میشه.
    من از SQL 2005 express و Collation Arabic_CI_AS استفاده می کنم.
  • #
    ‫۱۳ سال و ۱۲ ماه قبل، پنجشنبه ۲۹ مهر ۱۳۸۹، ساعت ۲۰:۲۲
    مشکل از SQL Server نیست. مشکل از درایور صفحه کلید شما است که به نظر ایراد دارد. باید ورودی کدهای خودتون رو در تمام قسمت‌هایی که insert دارد بررسی کنید (قبل از ورود به دیتابیس این تصحیح باید انجام شود مانند استفاده از تابع SafeFarsiStr فوق).
  • #
    ‫۱۳ سال و ۱۲ ماه قبل، پنجشنبه ۲۹ مهر ۱۳۸۹، ساعت ۲۰:۳۶
    اثبات این مدعا هم که مشکل از SQL Server نیست ساده است (فیلد با collation عربی ایجاد شده و ى فارسی در آن ثبت شده است و سپس گزارشگیری):
    DECLARE @tbl AS TABLE (f1 NVARCHAR(50) COLLATE Arabic_CI_AS NULL)
    INSERT INTO @tbl(f1) VALUES(NCHAR(1740))
    SELECT * FROM @tbl
  • #
    ‫۱۲ سال و ۳ ماه قبل، سه‌شنبه ۲۷ تیر ۱۳۹۱، ساعت ۱۵:۵۵
    واقعا عالی بود