مبانی الگوریتم دوسویه‌ی یونیکد

سوال

الگوریتم دوسویه (bidi) یونیکد اساساً چه کاری انجام می‌دهد؟

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

از ابتدا درک این نکته اهمیت داشته است که در تمامی مرورگرهای اصلی وب، ترتیب نویسه‌ها در حافظه (منطقی) با ترتیب نمایش داده شده آن‌ها (بصری) یکسان نیست.

مجموعه قوانینی که مرورگر برای ایجاد ترتیب صحیح در زمان نمایش اعمال می‌کند، توسط الگوریتم دوسویه‌ی یونیکد، یا به اختصار «الگوریتم bidi»، توضیح داده شده است.

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

مبانی الگوریتم دوسویه

نویسه‌ها و تایپ جهت‌دار

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

Examples of directionally typed words.

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

مرورگر شما چگونه تشخیص می‌دهد که یک رشته از نویسه‌ها باید از چپ به راست یا از راست به چپ نمایش داده شود؟ چون هر نویسه در یونیکد دارای یک ویژگی جهت‌دار مرتبط است. بیشتر حروف به‌صورت LTR (چپ به راست) تعریف شده‌اند. حروف مربوط به زبان‌هایی با نگارش راست به چپ به صورت RTL (راست به چپ) تعریف شده‌اند.

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

بخش‌های جهت‌دار

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

بنابراین، در مثال زیر، سه بخش جهت‌دار وجود دارد:

Left-to-right ordered directional runs: bahrain مصر kuwait.

بخش‌های جهت‌دار. مشاهده نسخه‌ی نمایشی زنده.

توجه داشته باشید که برای وقوع این فرآیند نیازی به نشانه‌گذاری یا ظاهر دادن ندارید.

جهت پایه، یک مفهوم اساسی

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

در HTML، جهت پایه یا به طور صریح توسط نزدیک‌ترین عنصر والد که از ویژگی dir استفاده می‌کند تعیین می‌شود، یا در صورت نبود چنین ویژگی‌ای، از جهت پیش‌فرض سند که چپ به راست است، به ارث می‌رسد.

نکته‌ی مهم اینجاست: ترتیب نمایش بخش‌های جهت‌دار در سراسر برگه وابسته به جهت پایه‌ی غالب بستگی دارد.

در مثال بالا که دارای زمینه‌ی کلی (یعنی جهت پایه) ltr است، شما ابتدا «bahrain»، سپس «مصر» و بعد «kuwait» را خواهید خواند.

Left-to-right ordered directional runs: bahrain مصر kuwait.

در یک زمینه‌ی LTR، بخش‌های جهت‌دار مشابه به همان ترتیب مورد انتظار اجرا می‌شوند. مشاهده نسخه‌ی نمایشی زنده.

اگر با تعیین جهت rtl برای عنصر html یا یک عنصر والد مانند div، p یا span، زمینه‌ی جهت‌گیری مثال بالا را تغییر دهید، ترتیب نمایش بخش‌های جهت‌دار نیز تغییر خواهد کرد.

Right-to-left ordered directional runs: bahrain مصر kuwait.

همان اجرای جهت‌دار در یک زمینه‌ی RTL. مشاهده نسخه‌ی نمایشی زنده.

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

نویسه‌های خنثی

فاصله‌ها و علائم نگارشی در یونیکد به صورت قوی به عنوان LTR یا RTL تعریف نشده‌اند، زیرا ممکن است در هر دو نوع خط مورد استفاده قرار گیرند. بنابراین، آن‌ها به‌عنوان نویسه‌های خنثی یا ضعیف دسته‌بندی می‌شوند.

نویسه‌ها معمولا زمانی که با شماره‌ها مرتبط هستند، به‌عنوان «ضعیف» دسته‌بندی می‌شوند. تعداد کمی از علائم نگارشی در ابتدا به‌عنوان نویسه‌های ضعیف دسته‌بندی می‌شوند، اما در یک زمینه‌ی غیرشمارشی، مانند نویسه‌های خنثی پردازش می‌شوند. بنابراین، در این مقاله، تمام علائم نگارشی را به‌عنوان نویسه‌های خنثی در نظر خواهیم گرفت.

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

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

Arabic words in an English sentence: The title is مفتاح معايير الويب in Arabic.

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

حتی اگر چندین نویسه خنثی بین دو نویسه با تایپ جهت‌دار قوی قرار بگیرند، همگی به همان روش پردازش خواهند شد.

توجه داشته باشید که برای این فرآیند همچنان نیازی به نشانه‌گذاری یا ظاهر دادن ندارید. همچنین، هنوز تنها سه بخش جهت‌دار در اینجا وجود دارد.

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

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

Arabic words in an English sentence: The title is مفتاح معايير الويب, in Arabic.

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

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

تعبیه‌کردن تغییرات در جهت پایه

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

Arabic words in an English sentence: The title is مفتاح معايير الويب! in Arabic.

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

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

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

زبان نشانه‌گذاری یا برنامه‌ای که با آن کار می‌کنید باید مکانیزم‌هایی برای انجام این تنظیمات در اختیار شما قرار دهد (به عنوان مثال، استفاده از ویژگی dir در یک عنصر q در HTML). در بخش فراتر از الگوریتم دوسویه این موضوع را بیشتر بررسی می‌کنیم.

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

Arabic words in an English sentence: The title is مفتاح معايير الويب! in Arabic.

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

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

شماره‌ها

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

one two ثلاثة 1234 خمسة  AND  one two ثلاثة ١٢٣٤ خمسة

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

اولین مثال از رقم‌های اروپایی «1234» استفاده می‌کند و مثال دوم همان شماره را با رقم‌های عربی-هندی ١٢٣٤ نمایش می‌دهد. در هر دو مورد، رقم‌های موجود از چپ به راست خوانده می‌شوند.

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

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

نویسه‌های آینه‌ای

همچنین خواهید دید که برخی نویسه‌ها بسته به جهت متنی که در آن قرار دارند، دارای شکل‌های آینه‌ای می‌شوند.

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

one two ثلاثة 1234 خمسة  AND  one two ثلاثة ١٢٣٤ خمسة

شکل‌های مختلفی برای یک نویسه پرانتز زاویه‌ای یکسان ارائه می‌شوند، بسته به جهت متن. مشاهده نسخه‌ی نمایشی زنده.

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

فراتر از الگوریتم دوسویه

لزوم تعیین جهت پایه

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

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

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

פעילות הבינאום, W3C

همان دنباله‌ی نویسه‌ها، با جهت پایه‌ی LTR یا RTL نمایش داده می‌شود. مشاهده نسخه‌ی نمایشی زنده.

هر رشته‌ای که متنی با بیش از یک جهت را ترکیب کند، نیاز دارد که اطلاعاتی درباره‌ی جهت پایه‌ی مناسب تنظیم شده باشد. در این مثال، W3C باید در سمت چپ متن ظاهر شود. اگر جهت پایه‌ی پیش‌فرض چپ به راست باشد، «W3C» در سمت راست متن عبری قرار می‌گیرد که ممکن است معنای متن را به طور قابل توجهی تغییر دهد یا حداقل باعث سردرگمی شود.

פעילות הבינאום, W3C

دنباله دیگری از نویسه‌ها، با جهت پایه‌ی LTR یا RTL نمایش داده می‌شود. مشاهده نسخه‌ی نمایشی زنده.

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

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

لزوم جداسازی محدوده‌های نزدیک

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

آنچه باید به نظر برسد.

AZZIP ELPRUP - 5 reviews

آنچه در واقع به نظر می‌رسد.

5 - AZZIP ELPRUP reviews

شماره‌هایی که پس از متن RTL در یک زمینه‌ی LTR قرار می‌گیرند، باید از متن قبلی جدا شوند. مشاهده نسخه‌ی نمایشی زنده.

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

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

The names of these states in Arabic are مصر, البحرين and الكويت respectively.

The names of these states in Arabic are مصر, البحرين and الكويت respectively.

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

برای جداسازی دو کلمه‌ی عربی از یکدیگر، نیاز به مداخله‌ی دستی وجود دارد. الگوریتم دوسویه نمی‌تواند این مسئله را به تنهایی حل کند.