เขียน PHP เพื่ออ่านไฟล์เวิร์ดจุฬา CU WRITER

ระลึกชาติกันเลยทีเดียว ได้เห็นโปรแกรมเวิร์ดจุฬา หรือ CU WRITER อีกครั้ง พร้อมเสียงเพลงตอนเปิดโปรแกรม

cw00

งานที่ต้องทำคืออ่านไฟล์ .cw แล้วบันทึกให้เป็นไฟล์ .txt เพื่อนำไปใช้งานอื่นๆ ต่อไป

ขอไม่กล่าวถึงการ copy ไฟล์ออกมา ถ้าไฟล์อยู่ในไดร์ฟ A ไม่ว่าจะเป็น 3.5 หรือ 5.25 นิ้ว คงต้องไปหาทางกันเอาเอง :)

ในที่นี้จะถือว่าคุณมีไฟล์ .cw อยู่ในเครื่องลีนุกซ์ที่ติดตั้ง PHP เรียบร้อยแล้ว เราจะมาเขียน PHP เพื่ออ่านไฟล์ .cw กัน

หมายเหตุ ด้วยความเคารพครับ ขออนุญาตอาจารย์ผู้เขียนโปรแกรม CU WRITER ด้วยครับ ที่ขอดูรูปแบบการเก็บไฟล์

สามารถดาวน์โหลดโปรแกรม CU WRITER ได้ที่

http://software.thaiware.com/download.php?id=1742

ต้องหา Windows ที่เป็น 32-bit เพื่อติดตั้งโปรแกรม CU WRITER

ตัวอย่างไฟล์ SMO.CW ที่เราจะเขียนโปรแกรม PHP อ่าน
cw01-smo

เพื่อความง่าย จะใช้ฟังก์ชัน fopen อ่านไฟล์ แล้วใช้ fread เพื่ออ่านข้อมูลในไฟล์ทั้งหมดไว้ในตัวแปร $contents

วนลูปทีละไบต์ แล้วใช้ฟังก์ชัน ord เพื่อแปลงค่าให้เป็นรหัส ASCII แล้ว echo พิมพ์ค่าออกมา

ตัวอย่างโปรแกรม PHP อ่านไฟล์

[dev@linux]$ vi read-cw.php
<?php

$fh = fopen("SMO.CW", "r");
$contents = fread($fh, filesize("SMO.CW"));

for ($i=0; $i<strlen($contents); $i++) {
    $ord = ord($contents[$i]);
    echo $ord . ' ';
}

fclose($fh);

ทดลองรันโปรแกรม

[dev@linux ~]$ php read-cw.php
27 27 161 162 164 167 32 97 98 99 100 13 10 27 27 23 161 162 164 167 32 97 98 99 100 27 23 13 10 27 27 19 161 162 164 167 32 97 98 99 100 27 19 13 10 27 27 18 161 162 164 167 32 97 98 99 100 27 18 13 10 27 27 2 161 162 164 167 32 97 98 99 100 27 2 13 10 27 27 5 161 162 164 167 32 97 98 99 100 27 5 13 10 27 27 19 23 161 162 164 167 32 97 98 99 100 27 19 23 13 10 27 27 19 23 2 5 161 162 164 167 32 97 98 99 100 27 19 23 2 5 13 10 27 28 161 162 164 167 32 97 98 99 100 28 13 10 27 28 23 161 162 164 167 32 97 98 99 100 28 23 13 10 27 29 161 162 164 167 32 97 98 99 100 29 13 10 27 30 161 162 164 167 32 97 98 99 100 30 13 10 27 26 79 80 84 32 49 46 53 48 1 0 0 0 0 0 0 0 0 0 0 0 4 33 8 66 16 132 33 8 66 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 80 0 32 0 1 0 4 0 78 0 19 0 110 0

วิธีการเก็บข้อมูลในไฟล์ .cw ค่อนข้างตรงไปตรงมา คือ 1 byte แทน 1 ตัวอักษร แล้วใช้ byte บางค่าเพื่อจัดรูปแบบเอกสาร เช่นตัวอักษร หรือขึ้นบรรทัดใหม่

ดีฟอลต์การเก็บข้อมูลของ CW จะเก็บในรูปแบบรหัส สมอ. ซึ่งจะตรงกับ TIS-620 เช่น

  • 161 = ก
  • 162 = ข
  • 97 = a
  • 98 = b
  • 32 = เว้นว่าง (space)

สามารถดูได้จากตารางในหน้าเว็บ Thai Industrial Standard 620-2533

ส่วนสองไบต์ติดกัน “13 10” น่าจะเป็นการขึ้นบรรทัดใหม่

ลองแก้โปรแกรม PHP เพิ่มตัวแปร array เก็บค่าการแปลงรหัส ASCII ให้เป็นตัวอักษร

แล้วเพิ่มการเช็คในลูปว่าถ้ามีค่าใน array ที่เก็บการแปลง ให้แสดงค่าออกมา

[dev@linux ~]$ vi read-cw.php
<?php

$fh = fopen("SMO.CW", "r");
$contents = fread($fh, filesize("SMO.CW"));

$smo_map = [
 '161' => 'ก',
 '162' => 'ข',
 '164' => 'ค',
 '167' => 'ง',
 '97' => 'a',
 '98' => 'b',
 '99' => 'c',
 '100' => 'd',
 '32' => ' ',
 '13' => "\n",
 '10' => '',
 ];

for ($i=0; $i<strlen($contents); $i++) {
    $ord = ord($contents[$i]);
    if (isset($smo_map[$ord])) {
         echo $smo_map[$ord];
    } else {
        echo $ord . ' ';
    }
}

fclose($fh);

ทดลองรันโปรแกรมอีกที

[dev@linux ~]$ php read-cw.php
27 27 กขคง abcd
27 27 23 กขคง abcd27 23
27 27 19 กขคง abcd27 19
27 27 18 กขคง abcd27 18
27 27 2 กขคง abcd27 2
27 27 5 กขคง abcd27 5
27 27 19 23 กขคง abcd27 19 23
27 27 19 23 2 5 กขคง abcd27 19 23 2 5
27 28 กขคง abcd28
27 28 23 กขคง abcd28 23
27 29 กขคง abcd29
27 30 กขคง abcd30
27 26 79 80 84 49 46 53 48 1 0 0 0 0 0 0 0 0 0 0 0 4 33 8 66 16 132 33 8 66 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 80 0 0 1 0 4 0 78 0 19 0 110 0

ส่วนค่าอื่นๆ เท่าที่ทดลองน่าจะเป็นการตั้งค่าตัวอักษรเช่น

  • 23 = ตัวเอียง
  • 19 = ขีดเส้นใต้ 1 เส้น
  • 18 = ขีดเส้นใต้ 2 เส้น
  • 2 = ตัวหนา
  • 5 = ตัวใหญ่
  • 27 นำหน้าแต่ละบรรทัดน่าจะเป็นการขึ้นบรรทัดใหม่
  • 27 การระบุชุดตัวอักษร 1
  • 28 ชุดตัวอักษร 2
  • 29 ชุดตัวอักษร 3
  • 30 ชุดตัวอักษร 4

ถ้าต้องการอ่านแค่ตัวอักษรอย่างเดียว ก็ไม่ต้องสนใจไบต์เหล่านี้ได้ หรือไม่ต้องพิมพ์ออกมา

ตัวอย่างการแก้โปรแกรมให้พิมพ์ตัวอักษรที่เราตั้งค่าการแปลงไว้ในตัวแปร $smo_map เท่านั้น

[dev@linux ~]$ vi read-cw.php
<?php

$fh = fopen("SMO.CW", "r");
$contents = fread($fh, filesize("SMO.CW"));

$smo_map = [
 '161' => 'ก',
 '162' => 'ข',
 '164' => 'ค',
 '167' => 'ง',
 '97' => 'a',
 '98' => 'b',
 '99' => 'c',
 '100' => 'd',
 '32' => ' ',
 '13' => "\n",
 '10' => '',
 ];

for ($i=0; $i<strlen($contents); $i++) {
    $ord = ord($contents[$i]);
    if (isset($smo_map[$ord])) {
        echo $smo_map[$ord];
    }
}

fclose($fh);

ส่วนตัวอักษรอื่นๆ รวมทั้งสระ ก็ใช้วิธีการแปลงค่า ASCII เหมือนกัน โดยดูจากตารางในหน้าเว็บไซต์ TIS-620 ได้

ลองรันโปรแกรมดูอีกครั้ง

[dev@linux ~]$ php read-cw.php
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd
กขคง abcd

ปัญหาอีกอย่างที่พบในไฟล์ .cw คือการตั้งค่ารหัสภาษาไทยเป็น “เกษตร” (เมนู “คำสั่งอื่นๆ” -> “เปลี่ยนรหัสภาษาไทย”)

ตัวอย่างไฟล์ที่บันทึกรหัสภาษาเป็น “เกษตร”

cw02-kaset

ถ้าเรารันโปรแกรมเดิม เพื่ออ่านไฟล์ ผลลัพธ์ที่ได้จะไม่ถูกต้อง

[dev@linux ~]$ php read-cw.php
กข abcd
กข abcd

สาเหตุเป็นเพราะมีการแปลงค่า ASCII ไม่ตรงกัน

แนะนำให้ copy ไฟล์โปรแกรม เป็นอีกไฟล์

[dev@linux ~]$ cp read-cw.php read-cw-kaset.php

แก้ไขไฟล์ ให้แสดงค่ารหัสที่แปลงไม่ได้

[dev@linux ~]$ vi read-cw-kaset.php
 <?php

$fh = fopen("KASET.CW", "r");
$contents = fread($fh, filesize("KASET.CW"));

$smo_map = [
    '161' => 'ก',
    '162' => 'ข',
    '164' => 'ค',
    '167' => 'ง',
    '97' => 'a',
    '98' => 'b',
    '99' => 'c',
    '100' => 'd',
    '32' => ' ',
    '13' => "\n",
    '10' => '',
];

for ($i=0; $i<strlen($contents); $i++) {
    $ord = ord($contents[$i]);
    if (isset($smo_map[$ord])) {
        echo $smo_map[$ord];
    } else {
         echo $ord . ' ';
    }
}

fclose($fh);

ลองรัน

[dev@linux ~]$ php read-cw-kaset.php
27 27 กข163 165 abcd
 27 27 23 กข163 165 abcd27 23 26 79 80 84 49 46 53 48 0 0 0 0 0 0 0 0 0 0 0 0 4 33 8 66 16 132 33 8 66 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 0 1 0 80 0 0 1 0 4 0 78 0 19 0 110 0

เท่าที่ดูผลลัพธ์ที่ได้ ‘ค’ น่าจะแปลงเป็น 163 ส่วน ‘ง’ น่าจะเป็น ‘165’

แก้ไขไฟล์ เพื่ออ้างอิงทีหลัง อาจเปลี่ยนชื่อตัวแปรจาก $smo_map เป็น $kaset_map

[dev@linux ~]$ cat read-cw-kaset.php
 <?php

$fh = fopen("KASET.CW", "r");
$contents = fread($fh, filesize("KASET.CW"));

$kaset_map = [
    '161' => 'ก',
    '162' => 'ข',
     '163' => 'ค',
     '165' => 'ง',
    '97' => 'a',
    '98' => 'b',
    '99' => 'c',
    '100' => 'd',
    '32' => ' ',
    '13' => "\n",
    '10' => '',
];

for ($i=0; $i<strlen($contents); $i++) {
    $ord = ord($contents[$i]);
    if (isset($kaset_map[$ord])) {
        echo $kaset_map[$ord];
    }
}

fclose($fh);

ลองรันโปรแกรมอีกครั้ง ก็น่าจะได้ผลลัพธ์ที่ถูกต้อง

[dev@linux ~]$ php read-cw-kaset.php
กขคง abcd
กขคง abcd

ส่วนตารางการแปลงค่ารหัส ASCII ของ “เกษตร” นั้น เท่าที่ลองหาดูบนเน็ตไม่พบ อาจต้องลองพิมพ์ตัวอักษรทั้งหมดแล้วเปรียบเทียบเอง

ข้อมูลอ้างอิง

1 thought on “เขียน PHP เพื่ออ่านไฟล์เวิร์ดจุฬา CU WRITER”

  1. สำหรับตารางการแปลงค่ารหัสเกษตรของเวิร์ดจุฬา ผมได้ reverse engineer จากไฟล์ของเวิร์ดจุฬาเมื่อนานมาแล้วครับ
    https://github.com/kytulendu/Stuff/blob/master/TCONV/CWKU2STD.H
    นอกจากนี้ใน github ของผมยังมีตารางสำหรับแปลงรหัสเกษตรของราชวิถีเวิร์ดเป็น TIS-620 ที่ใช้รหัสการตีตารางไม่เหมือนกับของเวิร์ดจุฬาด้วยครับ

    ส่วนรูปแบบไฟล์ของเวิร์ดจุฬา ผมได้ศึกษาโดยใช้ Hex Editor มาแล้วส่วนหนึ่ง โดยเฉพาะรหัสการตีตาราง, Dot Command ที่มีความคล้ายกับ WordStar และค่า option ท้ายไฟล์ (เวิร์ดจุฬา รุ่น 1.50 ขึ้นไปจะสามารถเก็บ option ไว้ท้ายไฟล์ได้) แต่ไม่ได้ศึกษาต่อ ตัวเอกสารอาจดูไม่ค่อยเป็นระเบียบมากนักนะครับ
    https://github.com/kytulendu/CW141/wiki/File-Format

    ตอนแรกๆผมกะจะเอาข้อมูลรูปแบบไฟล์นี้เอาไปลองเขียน import filter ของ LibreOffice ครับ กะจะให้อ่านได้ทั้งไฟล์ของเวิร์ดจุฬาบนดอส และไฟล์ของจุฬาจารึกหรือเวิร์ดจุฬาสำหรับวินโดวส์ (รองรับรูปภาพที่แทรกอยู่ในไฟล์ด้วย) แต่ก็พักไว้เพราะไม่รู้จะเริ่มตรงไหนดีและดูแล้วมันซับซ้อนมากสำหรับความสามารถของผมในขณะนั้นครับ

Leave a Reply