แปลงเลขไทย เป็น int

Posted 10/08/2011 00:16 by nantcom

Internet

พอดีว่า ผมกำลังซุ่มทำอะไรบางอย่างอยู่ ซึ่งต้องไปยุ่งกับเลขไทย แต่ปรากฏว่า ผมลองหาดูแล้ว int.Parse นั้น ไม่ยอมแปลงเลขไทย ครับ มันไม่ยอมเอา CultureInfo.NumberFormat.NativeNumbers มาใช้ ผมก็เลยต้องเขียนเองอีกแล้วดิ!

ฟังก์ชั่นก็ไม่ยากครับ ผมสร้าง Dictionary ขึ้นมาก่อน เอาไว้เก็บเทียบกันว่า ‘๑’ คือ 1 อะไรแบบนี้

Code Snippet
  1. private static Dictionary<char, char> _ThaiNativeDigits =
  2.     ("?,?,?,?,?,?,?,?,?,?").Split(',').ToDictionary(s => s[0], s => (char)('0' + (s[0] - '?')));
  3. private static int ParseThaiNativeDigits( string input )
  4. {
  5.     StringBuilder sb = new StringBuilder(input);
  6.     for (int i = 0; i < sb.Length; i++)
  7.     {
  8.         sbIdea = _ThaiNativeDigits[sbIdea];
  9.     }
  10.  
  11.     return int.Parse(sb.ToString());
  12. }

(เนื่องจากไอ้ตัว Plugin Paste โค๊ด มันไม่รับภาษาไทย (อีกแล้ว!!!) ตรงที่เป็น ????? คือ "๐,๑,๒,๓,๔,๕,๖,๗,๘,๙" ครับ และตรง s[0] – ‘?’ คือ s[0] – ‘๐’)

จากนั้น ผมก็เล่นง่ายๆ ครับ ลบเลขธรรมดา คือว่า ‘๙’ มันจะห่างจาก ‘๐’ 9 ตัวพอดีครับ ผมก็เลยเอามันมาลบกัน ( s[0] – ‘๐’) เพื่อออกมาเป็นตัวเลขก่อน จากนั้น ผมจะแปลงมันกลับเป็นเลขอารบิก ก็เลยต้องเอา ‘0’ บวกเข้าไป จากนั้น ก็แปลงค่าจาก int กลับเป็น char

ตัวอย่างเช่น

'๑' คือ 3665
’๐’ คือ 3664

3665 – 3664 = 1

และ ‘0’ คือ 48 ดังนั้น 48 + 1 = 49

ซึ่ง 49 ก็คือ ‘1’ นั่นเอง

เสร็จแล้ว ผมก็จับมันใส่ StringBuilder (รู้ไหมว่าทำไม???) แล้วก็แปลงแบบบ้านๆ เลย คือ Map จากเลขไทย เป็นเลขอารบิก แล้วก้อใช้ int.Parse อีกที แน่นอนว่า Function มันจะ Error ถ้าเกิดว่า มีข้อมูลที่ไม่ใช่เลขไทยนะครับ อันนี้ก็ต้องแก้ไขต่อกันเอง

แล้วเรื่องแปลกก็คือ เหอๆ แต่เชื่อหรือไม่ครับ ว่า คนที่ใช้ภาษาอารบิก ก็ดั๊น มีปัญหาเดียวกันเลย (เจอใน StackOverflow) เพราะเลขอารบิกของเขา มันเขียนไม่เหมือนของเราครับ เหอๆ (เขียนแบบ Aracib-indic)

image

ร่วมให้กำลังใจนักเขียน

อ่านแล้วชอบใจ อยากให้กำลังใจกับผู้แต่งบทความนี้ ขอเชิญร่วมให้กำลังใจผ่าน Paysbuy/Paypal นะครับ ปลอดภัยเพราะทำงานผ่าน SSL และไม่มีค่าใช้จ่ายเพิ่มเติมครับ เว็บเราให้นักเขียน 100% ครับ

Comment ระบบเก่า

 

hisoft said:

ตอนนี้ผมลองใช้แบบนี้แปลงไป - กลับดูน่ะครับ ไม่แน่ใจว่าดี/ไม่ดียังไง รบกวนแนะนำด้วยครับ

private static int ParseThaiNativeDigits(string input)

       {

           for (int i = 0; i < 10; i++)

           {

               input = input.Replace("" + (char)('๐' + i), "" + (char)('0' + i));

           }

           return int.Parse(input);

       }

       private static String ToThaiNativeDigits(string input)

       {

           for (int i = 0; i < 10; i++)

           {

               input = input.Replace("" + (char)('0' + i), "" + (char)('๐' + i));

           }

           return input;

       }

August 13, 2011 3:04 AM
 

nantcom said:

ระวังตรง input = input.Replace ครับผม เพราะว่า เวลาสั่ง Replace 1 ครั้ง มันจะสร้าง String ใหม่ 1 ตัว ถ้ารันไปนานๆ มันอาจมีปัญหากินแรมเยอะได้ครับ (รันฟังก์ชั่นนี้ 1 ครั้ง เกิด string ใหม่ได้ถึง 10 ตัว) แต่ถ้าโปรแกรมไม่ได้รันนาน (Windows App) ก็ไม่มีผลอะไรครับผม

เช่น ตอนแรก มีแค่ "๑๒๓๔๕๖๗๘๙๐"

Replace 1 ที

"๑๒๓๔๕๖๗๘๙๐",  "๑๒๓๔๕๖๗๘๙0"

Replace 2 ที

"๑๒๓๔๕๖๗๘๙๐",  "๑๒๓๔๕๖๗๘๙0","1๒๓๔๕๖๗๘๙0"

Replace 3 ที

"๑๒๓๔๕๖๗๘๙๐",  "๑๒๓๔๕๖๗๘๙0","1๒๓๔๕๖๗๘๙0", ","12๓๔๕๖๗๘๙0"

....

August 13, 2011 10:33 AM
 

hisoft said:

อ่อครับ อันตรายแบบนี้นี่เองผมจะได้จำไว้บ้าง ขอบคุณที่แก้ขอสงสัยให้นะครับ ^^ ตอนแรกผมนึกว่ามันจะกำจัดตัวเก่าทิ้งไปเองเลย

ถ้าอย่างนั้นหากเราจำเป็นต้องใช้ฟังก์ชัน replace มีวิธีไหนจะช่วยล้างค่าที่ไม่ใช้ได้ครับ? ผมเคยเรียนแต่ java เลยไม่มีความรู้เกี่ยวกับการกำจัดพวกนี้เท่าไหร่ เข้าใจว่า java ทำการโละให้เองด้วยใช่ไหมครับ?

August 14, 2011 2:51 AM
 

nantcom said:

Java ก็ทำแบบเดียวกันครับ เพราะ String ของ Java/C# เป็น en.wikipedia.org/.../Immutable_object

ถ้าจะ Replace แบบ "in-place" ต้องใช้ StringBuilder ครับ สำหรับ C# แต่จะมีประโยชน์ต่อเมื่อ Replace หลายๆ รอบเท่านั้น เพราะว่ามันต้อง Copy String 1 รอบก่อน แล้วก้อ Copy ออกมา 1 อีกรอบ เช่น

StringBuilder buffer = new StringBuilder( "๑๒๓๔๕๖๗๘๙๐");

for (int i = 0; i < 10; i++)

{

    // สังเกตว่า ตัวนี้ Return Void

    buffer.Replace("" + (char)('๐' + i), "" + (char)('0' + i));

}

value = int.Parse(buffer.ToString());

แต่ถ้าเป็นพวกคิดมากแบบผม ก็คือ Replace มันอาจจะยังต้องไปอ่าน String ทั้งหมดอีกหลายรอบ จึงจะ Replace ได้ครบ หรือก็คือ Loop 1 ถึง 10 แต่ละ Loop อาจจะมี Loop ใน Function Replace อีกซ้อนเข้าไป ดังนั้น 10 Loop ข้างนอก รันเข้าจริงๆ อาจจะเป็น 10xn (n = ความยาว string) ได้ครับ ดังนั้นผมจึงใช้วิธี Map ค่า แต่ละตัวใน Array จากเลขไทย เป็นเลขอารบิค ครับผม :) เพราะว่า แบบนี้ มันจะรันแค่ n ครั้งเท่านั้น

แต่ถ้าเรียนมา จะพบว่า Big-O ของ O(10n) กับ O(n) เท่ากันนะ ดังนั้น ถ้าทำแบบนี้ไปแล้ว ไม่ต้องไล่กลับไป "Micro-Optimize" :D อีกอย่าง ก็อย่างที่ผมบอกครับ มันมีผลน้อยมาก (นอกจากระบบที่รันนานๆ) แต่ว่าเวลาเขียน ผมคิดแบบนี้ไว้แต่ต้นครับผม

แล้วก็ Java/C# มี Garbage Collector ครับ มันจะ Clear ให้เอง "ถ้า Clear ได้" ถ้าเกิดว่าเรา Replace ใน Loop แบบเร็วๆ บางทีมันก็เกิด OutOfMemory ได้ครับเพราะว่า Heap เต็ม มัน Clear ไม่ทัน  (ซึ่งแก้ได้ใน C# โดยใส่ GC.Collect() บังคับให้มันทำงาน แต่ทำให้โปรแกรมช้าลงนะ) หรือว่าเกิด Heap Fragmentation คือ Clear แล้วแต่ว่าไม่มีที่ว่างใหญ่พอจะใส่ของใหม่ลงไป :) ซึ่งอันนี้แก้ไม่ได้ :P

August 15, 2011 8:57 AM
 

hisoft said:

อ่อครับ เข้าใจเพิ่มขึ้นเยอะเลย ขอบคุณครับ

August 16, 2011 2:25 PM
(required)  
(optional)
(required)  
Add

DisQUS Comment (ยังเอ๋อๆ อยู่)

blog comments powered by Disqus