شیء Intl.Segmenter ابزاری فوقالعاده کاربردی برای تکهتکه کردن و شکستن یک رشته متنی به بخشهای معنادار (Segments) است. بدون استفاده از مجموعه Intl، شما کماکان میتوانید یک رشته را بر اساس واحدهای UTF-16 یا کدهای یونیکد (Unicode code points) تکهتکه کنید:
const str = "🇺🇸🇨🇳🇷🇺🇬🇧🇫🇷";
console.log(str.split(""));
// خروجی یک آرایه ۲۰ تایی از کدهای مجزاست: ['\uD83C', '\uDDFA', '\uD83C', ...]
console.log([...str]);
// خروجی یک آرایه ۱۰ تایی از کدهای یونیکد است: ['🇺', '🇸', '🇨', '🇳', '🇷', '🇺', '🇬', '🇧', '🇫', '🇷']
اما همانطور که در خروجی بالا میبینید، کدهای یونیکد با چیزی که ما انسانها به عنوان یک «کاراکتر واحد و مستقل» درک میکنیم، کاملاً متفاوت هستند! این اتفاق بیشتر در اموجیها رخ میدهد؛ جایی که یک اموجی واحد (مثل پرچم یک کشور) ممکن است از ترکیب چندین کد یونیکد مختلف تشکیل شده باشد.
زمانی که یک کاربر با متن تعامل دارد، گرافیم (Grapheme) کوچکترین واحد متنی است که میتواند آن را دستکاری کند (مثلاً آن را انتخاب یا پاک کند). شیء Segmenter به ما اجازه میدهد بخشبندی را در سطح گرافیم انجام دهیم که برای کارهایی مثل شمارش دقیق کاراکترها، محاسبه عرض متن و... حیاتی است. این ابزار یک رشته را میگیرد و یک شیء قابلپیمایش (Iterable) برمیگرداند که هر عنصر آن دارای ویژگی segment (حاوی متنِ آن بخش) است:
// ساخت یک بخشبندیکننده در سطح گرافیم (کاراکترهای قابل درک انسان)
const segmenter = new Intl.Segmenter("en-US", { granularity: "grapheme" });
console.log([...segmenter.segment("🇺🇸🇨🇳🇷🇺🇬🇧🇫🇷")].map((s) => s.segment));
// خروجی دقیق و درست: ['🇺🇸', '🇨🇳', '🇷🇺', '🇬🇧', '🇫🇷']
این ابزار علاوه بر کاراکترها، میتواند بخشبندی را در سطوح بالاتر یعنی در سطح کلمات و جملات نیز انجام دهد. این سناریوها کاملاً وابسته به زبان و فرهنگ هدف هستند. به عنوان مثال، کد زیر یک نمونهی بسیار ضعیف و غیراستاندارد برای شمارش تعداد کلمات است:
const wordCount = (str) => str.split(/\s+/).length;
console.log(wordCount("Hello, world!")); // خروجی: 2
این روشِ سنتی چند ایراد بزرگ دارد: همه زبانهای دنیا از فاصله (Space) برای جدا کردن کلمات استفاده نمیکنند، همه فضاهای خالی به معنی جداکننده کلمه نیستند، و همه کلمات هم با فاصله از هم جدا نمیشوند!
برای حل این مشکل، کافی است Segmenter را با گزینه { granularity: "word" } بسازید. خروجی این کار، رشته ورودی شماست که به بخشهایی از «کلمات» و «غیرکلمات» (مثل فاصلهها و علائم نگارشی) تقسیم شده است. اگر هدف شما صرفاً شمارش کلمات واقعی است، میتوانید بخشهای غیرکلمه را با بررسی ویژگی isWordLike فیلتر کنید:
const segmenter = new Intl.Segmenter("en-US", { granularity: "word" });
const str = "It can even split non-space-separated words";
console.table([...segmenter.segment(str)]);
خروجی متد console.table ساختار زیر را به وضوح نمایش میدهد:
| segment | index | isWordLike |
'It' | 0 | true |
' ' | 2 | false |
'can' | 3 | true |
' ' | 6 | false |
'even' | 7 | true |
' ' | 11 | false |
'split' | 12 | true |
' ' | 17 | false |
'non' | 18 | true |
'-' | 21 | false |
'space' | 22 | true |
'-' | 27 | false |
'separated' | 28 | true |
' ' | 37 | false |
'words' | 38 | true |
حالا به راحتی با فیلتر کردن بر اساس isWordLike میتوانیم کلمات واقعی را استخراج کنیم:
console.log(
[...segmenter.segment(str)].filter((s) => s.isWordLike).map((s) => s.segment)
);
// خروجی: ['It', 'can', 'even', 'split', 'non', 'space', 'separated', 'words']
بخشبندی کلمات برای زبانهای مبتنی بر نویسه (Character-based) که از فاصله استفاده نمیکنند هم به معجزه تبدیل میشود! مثلاً در زبان چینی، چندین کاراکتر در کنار هم یک کلمه واحد را تشکیل میدهند اما هیچ فاصلهای بین آنها وجود ندارد. این ابزار دقیقاً همان رفتاری را پیادهسازی میکند که مرورگرها هنگام دو بار کلیک کردن روی یک کلمه برای انتخاب آن انجام میدهند:
const segmenter = new Intl.Segmenter("zh-Hans", { granularity: "word" });
console.log([...segmenter.segment("我是这篇文档的作者")].map((s) => s.segment));
// خروجی هوشمندانه: ['我是', '这', '篇', '文', '档', 'of', '作者']
تشخیص مرز جملات نیز پیچیدگیهای خاص خود را دارد. به عنوان مثال، در زبان انگلیسی علائم نگارشی متعددی (.، !، ? و...) وجود دارند که میتوانند نشاندهنده پایان یک جمله باشند:
const segmenter = new Intl.Segmenter("en-US", { granularity: "sentence" });
console.log(
[...segmenter.segment("I ate a sandwich. Then I went to bed.")].map((s) => s.segment)
);
// خروجی: ['I ate a sandwich. ', 'Then I went to bed.']
📌 نکته مهم: ابزار
Segmenterهیچ کاراکتری (مثل علائم نگارشی یا فاصلهها) را از متن حذف نمیکند؛ بلکه صرفاً رشته را به تکههایی تقسیم میکند که هر تکه یک جمله کامل است. اگر مایل باشید، میتوانید علائم نگارشی را بعداً خودتان با کد فیلتر کنید.همچنین به یاد داشته باشید که پیادهسازی فعلی این ابزار هنوز ترفندهای استثنائی پایان جمله را پشتیبانی نمیکند (مثلاً ممکن است بعد از نقطهی کلمات مخففی مثل
".Mr"یا".Approx"به اشتباه جمله را قطع کند)، اما تلاشها و فرآیندهای توسعه در استاندارد اکمااسکریپت برای اضافه شدن این قابلیت در جریان است.
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://developer.mozilla.org/en-US/docs/Web/JavaScript