#!/usr/bin/perl
######################################################################
# eg/th/mb_practical.pl - ตัดคอลัมน์คงที่โดยไม่ทำให้ตัวอักษรเสีย
#
# ตัวอย่างนี้แสดงอะไร (งานจริงเล็ก ๆ):
#   ตัดบรรทัด Shift_JIS ให้เหลือ DISPLAY WIDTH คงที่สำหรับเอาต์พุตแบบ
#   คอลัมน์คงที่ โดยนับตัวอักษรครึ่งความกว้างเป็น 1 คอลัมน์ และตัวอักษร
#   เต็มความกว้างเป็น 2 คอลัมน์ (อัตราส่วนคลาสสิก 1:2) และไม่เคยผ่าตัวอักษร
#   สองไบต์ที่เส้นแบ่ง
#
# ต่างจาก CORE อย่างไร:
#   CORE substr(EXPR, 0, N) แบบไร้เดียงสาตัดที่ OCTET ที่ N และอาจทิ้ง
#   lead byte ค้างไว้ -- ครึ่งตัวอักษรที่พัง ที่นี่เราเดินทีละตัวอักษรทั้งตัว
#   ด้วย mb::split('') วัดความกว้างของแต่ละตัวจากความยาวไบต์ของมัน (1 ไบต์
#   -> 1 คอลัมน์, 2 ไบต์ -> 2 คอลัมน์) และหยุดก่อนเกินงบ mb::length()
#   ยืนยันว่าผลลัพธ์เป็นจำนวนตัวอักษรเต็มจำนวน
#
# ซอร์สเป็น US-ASCII; ข้อมูล multibyte ใช้ไบต์เอสเคป \xHH เป็น runtime
# interface เท่านั้น จึงทำงานบน perl ทุกตัวตั้งแต่ 5.005_03 ขึ้นไป
#
#     perl eg/th/mb_practical.pl
#
######################################################################
use strict;
use vars qw($line $budget $out $col $ch $w $aiu $octet_cut $char_cut);

use FindBin;
use lib "$FindBin::Bin/../../lib";
use mb;
mb::set_script_encoding('sjis');

# A B C แล้วฮิรางานะเต็มความกว้างสามตัว a i u แล้วคาตาคานะครึ่งความกว้างสองตัว
#   ASCII A B C            : ตัวละ 1 คอลัมน์
#   เต็มความกว้าง a(\x82\xA0) i(\x82\xA2) u(\x82\xA4) : ตัวละ 2 คอลัมน์
#   ครึ่งความกว้าง ka(\xB6) ki(\xB7)                  : ตัวละ 1 คอลัมน์
$line   = "ABC\x82\xA0\x82\xA2\x82\xA4\xB6\xB7";
$budget = 7;   # ตัดให้เหลือ 7 คอลัมน์แสดงผล

# ตัดแบบปลอดภัยที่ขอบตัวอักษรและรู้ความกว้าง
$out = '';
$col = 0;
for $ch (mb::split('', $line)) {
    $w = length($ch);        # 1 ไบต์ -> 1 คอลัมน์, 2 ไบต์ -> 2 คอลัมน์
    last if $col + $w > $budget;
    $out .= $ch;
    $col += $w;
}

# ABC (3 คอลัมน์) + a (2) + i (2) = 7 คอลัมน์; u จะล้นและถูกตัดทิ้ง ดังนั้น
# ตัวอักษรสองไบต์ตัวท้ายจึงยังครบตัว
print "input chars      : ", mb::length($line), "\n";        # 8
print "budget columns   : $budget\n";                        # 7
print "kept chars       : ", mb::length($out), "\n";         # 5
print "used columns     : $col\n";                           # 7
print "kept bytes       : ", length($out), "\n";             # 7

# เปรียบเทียบกับข้อมูลที่เป็นสองไบต์ล้วน: การตัดที่จำนวน OCTET คงที่อาจตกลง
# ภายในตัวอักษร ฮิรางานะ a i u เป็นสองไบต์ทั้งหมด ดังนั้นความยาวไบต์ที่เป็น
# เลขคี่หมายความว่าการตัดผ่าตัวอักษร; mb::substr หยุดที่ขอบตัวอักษรเสมอ
# (ความยาวไบต์เป็นเลขคู่ที่นี่)
$aiu       = "\x82\xA0\x82\xA2\x82\xA4";
$octet_cut = substr($aiu, 0, 3);        # a + lead byte ค้าง
$char_cut  = mb::substr($aiu, 0, 1);    # a พอดี
print "CORE substr 3oct : ", length($octet_cut), " bytes (odd -> split)\n"; # 3
print "mb::substr 1char : ", length($char_cut),  " bytes (whole char)\n";   # 2

exit 0;
