ตัดคำไทยด้วย C#

by m3rLinEz 5. March 2010 02:15

WARNING: Highly technical blog ahead

กาลครั้งหนึ่งนานมาแล้ว … อาจารย์สมชายแห่ง CP เคยเอารัฐธรรมนูญฉบับเก่ากับฉบับใหม่มาเทียบความถี่ในการปรากฎของคำ ตอนนั้นผมอึ้งมากที่รู้ว่า Java มันตัดคำไทยได้ด้วย แบบ built-in มาไม่ต้องหา library อะไรมาเพิ่มเลย >_<  ถ้าผมเข้าใจไม่ผิด Java ใช้ ICU ของ IBM ที่เป็น open source แต่ตัวที่อยู่ใน class library ของ Java จะเป็นเวอร์ชันเก่ากว่าหน่อย

เจ้า ICU ที่ว่านี่นอกจากตัดคำได้ (Boundary Analysis) แล้วมันยังทำอย่างอื่นที่เกี่ยวกับกับ localization & internationalization ได้อีกมากมายก่ายกองครับ ลองเข้าไปดูกันเอง IBM ทำไว้สองชุดคือ ICU4C และ ICU4J สำหรับ C, C++ และ Java (ไม่มี .NET แป่วว) ถ้าใครทันสมัยใช้ Firefox ที่ยังตัดคำไทยไม่ค่อยจะคล่องอาจจะได้ยินชื่อนี้บ่อย เพราะมีคนไทยฮาร์ดคอร์มากมายเอาโค้ด Firefox มาแก้ใส่ ICU ให้ตัดคำแล้ว build ใหม่ … แค่ฟังก็อยากจะอ้วกออกมาเป็น pointer กับไฟล์ .h แล้วว =__=’

ด้วยความที่ 3 วันนี้ผมเมาจัดหรือยังไงไม่ทราบ เลยใช้เวลาว่างอันมีอยู่น้อยนิดไปพยายามทำ binding ให้เรียกใช้ ICU จาก C# (และ .NET) ได้ครับ! ก่อนทำก็หา best practice โดยการไปถามที่แหล่งประจำเล็กน้อย ได้คำตอบมาแค่อันเดียวน่าเศร้าใจ TvT

ผมเข้าใจว่าการทำ binding มันจะต่างจาก wrapper ตรงที่ เราต้องนำเสนอ interface เดียว (หรือคล้ายๆ) กับที่ underlying C++ classes มันใช้อยู่ให้กับผู้ใช้ ส่วนการทำ wrapper มันเหมือนกับว่าเราไปสร้างอะไรซักอย่างหุ้ม C++ classes เหล่านั้นไว้ และให้ผู้ใช้เรียกใช้งานผ่าน interface ของเรา (โดยไม่รู้ว่าข้างในมีอะไรอยู่บ้าง – Facade Pattern อ่านว่า “ฟา-ซ้าด”) ซึ่งการทำ wrapper นี่มันง่ายกว่าโขเลยน่ะ

หลังจากลองถูๆไถๆ ใช้พลังกับ C++/CLI เหมือนที่เคยใช้ในซีเนียร์โปรเจค ก็ออกมาเป็นรูปเป็นร่าง อยู่ที่ ICU4NET สามารถลองดาวน์โหลดไปใช้ได้ ถึงชื่อจะบอกว่า ICU4NET แต่จริงๆแล้วตอนนี้มันมี class ที่ใช้งานได้อยู่ class เดียวคือ BreakIterator =_=” ตั้งใจไว้ว่าจะจัดการกับ class ในกลุ่ม boundary analysis ให้หมด

เอาโค้ดตัวอย่างให้ดูเล็กน้อย อันแรกเป็นแบบดั้งเดิม ลักษณะเดียวกับที่เขียนใน ICU4J และ ICU4C

private List<string> WordBreak(string text)
{
var sb = new StringBuilder();
var col = new List<string>();

using (BreakIterator bi = BreakIterator.CreateWordInstance(Locale.GetUS()))
{
bi.SetText(text);
int start = bi.First(), end = bi.Next();
while (end != BreakIterator.DONE)
{
col.Add(text.Substring(start, end - start));
start = end; end = bi.Next();
}
}

return col;
}

ส่วนอันนี้ผมเขียน Extension Method เพิ่มให้มัน return เป็น IEnumerable ได้ พวกขา 3.5 จะได้เล่นซนแบบนี้ได้ :’)

using (BreakIterator bi = BreakIterator.CreateWordInstance(Locale.GetUS()))
{
bi.SetText(uxText.Text);

// requires ICU4NETExtension to use Enumerate extension method
MessageBox.Show(string.Join(Environment.NewLine, bi.Enumerate()
.GroupBy(w => w)
.OrderBy(x => x.Count())
.Reverse()
.Select(x => x.Key + " : " + x.Count())
.Take(10)
.ToArray()));
}

ตอนแรกตั้งใจว่า ส่วนที่น่าจะเอาไปเล่นได้หลักๆคงเป็นพวก ASP.NET Web App แหละ แต่นั่งคิดๆดูแล้วมันมีส่วนประกอบที่เป็น library native ของ ICU หลายอันอยู่ ถ้าเข้าใจไม่ผิดคงมีปัญหากับเรื่อง trust level ของ IIS พอสมควร …

ผลพลอยได้จากการผลาญเวลา (แบบไร้เหตุผล เอามันส์ล้วนๆ) ครั้งนี้คือ ได้ศึกษา C# เพิ่มอีกนิดหน่อย แล้วก็ลองใช้ C++/CLI อีกนิสสสนึง หลังๆมานี่อยู่ที่ทำงานได้ใช้แต่ C++ จนรู้สึกตัวเองตามโลก C# ไม่ทัน มาอ่านโค้ดของ @chakrit (ขา 3.5 ตัวพ่อ) ทีนี่นั่งงงอยู่หลายนาที –..-‘ เออออ … น้ำหลักลดด้วยนะ ^ ^

จากประสบการณ์ ด้วยหัวข้อยบลอกประมาณนี้ ผมเชื่อว่าคงมี นิสิต/นักศึกษา ที่กำลังปั่นงานของอาจารย์แล้ว search มาเจอ และอยากนำไปใช้ได้โดยเร็ว … ผมขอร้องว่าก่อนจะทิ้งคอมเม็นต์ไว้หรือเมล์มาถาม technical issue กับผม ช่วยศึกษาเรื่องพื้นฐาน C# กับเรื่องพวกวิธี reference รวมถึงอ่าน Readme ก่อน แล้วค่อยถามมานะครับ …

ผมตั้งเป้าไว้ว่าจะมีคนเอาไปใช้ประโยชน์ได้ 2 คนขึ้นไป ใครเอาไปใช้ทำอะไรบอกด้วยๆ :’)

ICU4NET – ICU Binding for .NET

WordBreak

Tags: , , , , , , Category: OOAD | .NET | Java | Native

Comments (30) -

Zolo
Zolo
3/5/2010 8:27:26 AM #

เยี่ยมไปเลยนาย เหมือนว่าเราจะต้องไปนั่งดู​ ICU เหมือนกันอะ ฮา ๆ

Zolo
Zolo
3/5/2010 9:02:15 AM #

เยี่ยมไปเลย กำลังจะได้เล่น ICU เลยหละมั้ง ฮาๆ

tot-anusak
tot-anusak
3/5/2010 9:10:41 AM #

เป็นงานเป็นการมากมาย O.o

Nuke
Nuke
3/5/2010 10:03:42 AM #

ผมเพิ่งรู้เร็วๆนี้เองว่า Java มี BreakIterator ที่ตัดคำได้ที่เอามาจาก ICU ลองเล่นดูใน Java แล้วเหมือนว่ามันใช้ dict ด้วยรึป่าว (อันนี้ไม่รู้) เจอชื่อเฉพาะมันก็ตัดแปลกๆนะ

อรุช
อรุช
3/6/2010 3:39:28 AM #

Geek มาก!

Bewilder
Bewilder
3/8/2010 2:20:23 AM #

เราอ่านแล้วไม่เข้าใจว่าทำไมต้องทำ Binding ทำไมถึงทำเป็น Wrapper ไม่ได้ อะ

m3rlinez
m3rlinez
3/8/2010 8:20:09 PM #

@อู๋ IBM Thailand ได้ทำ ICU ด้วยเหรอวะ ดีๆๆ
@โตโต้ ตั้งใจทำกว่าที่บ.อีกนะเนี่ย แอร๊ย ไม่ใช่
@Nuke ใช่แล้วครับ ICU มันใช้ dict ตัดนั่นแหละ ขนาด dict ภาษาไทยประมาณ 500 KB
@อรุช แน่น๊อนนน
@รุต ถ้ามองในแง่ฟังก์ชัน จะ wrap หรือจะทำ binding มันก็ได้เหมือนกันนะ เพียงแต่ถ้าอยากตั้งชื่อโปรเจคว่า ICU4NET (ซึ่งเราอยาก) ตัว interface ข้างใน (classes, methods) มันควรจะเหมือนกับ ICU4C, ICU4J อ่ะ ไม่รู้ตอบตรงคำถามรึเปล่า ?

อรุช
อรุช
3/10/2010 1:18:24 AM #

เข้าลิงค์เว็บชาไม่ได้ว่ะ

m3rlinez
m3rlinez
3/10/2010 4:54:01 AM #

@อรุช รู้สึกเค้าจะเปลี่ยนชื่อ repo http://github.com/chakrit/fu-sharp

chakrit
chakrit
3/25/2010 2:39:30 PM #

Cool Smile

Back where I used to work my friend created an internal database search engine implementation once using Lucene.NET and it can't break thai words - -'

Now it can!

amd thanks for link up on fu# Smile

ob
ob
5/4/2010 11:01:37 AM #

ลองเอาไปใช้แล้วใช้ไม่ได้ครับ มันบอก error ว่าไม่เจอ ICU4NET Version=1.0.3716.970 ผมเอา DLL ทั้งหมด ใน Package ที่ Download มาไปไว้ตำแหน่งที่เก็บ EXE แล้วครับ แต่ยังไม่ได้ หรือมีให้ Download ตัวที่เป็น DLL ของ IBM ได้ที่ไหนครับ หรือผมจะดึง Dictionary ที่คุณเอามาใช้ได้จากที่ไหน

m3rlinez
m3rlinez
5/4/2010 3:22:31 PM #

คุณ ob ใช้งานโปรแกรมตัวอย่างที่ติดไปได้รึเปล่าครับ ?

ob
ob
6/8/2010 10:54:10 AM #

ผมใช้ VS.NET C# 2005 พอลง 2008 ใช้ได้ครับ น่าจะเกี่ยวกับ Version .Net Framework รึเปล่าไม่แน่ใจ แล้วสามารถนำไปใช้กับ VB6 ได้รึเปล่าครับ

333CS
333CS
6/26/2010 12:11:44 PM #

ขอบคุณมากค่ะ  สำหรับบทความนี้ พอดีกำลังทำโปรเจคเรื่องนี้อยู่พอดี  เกี่ยวกับการตรวจสอบคำสะกดบนเวบบอร์ด ได้ลองใช้โปรแกรมที่ให้ไปแล้ว
ว่าจะใข้ vs 2008 เขียน  เป็นไปได้ไหมคะ และควรจะทำอย่างไรบ้าง  ช่วยชี้แนะหน่อยค่ะ

m3rlinez
m3rlinez
6/27/2010 2:27:39 PM #

@333CS ใช้ได้แน่นอนครับ แต่ผมแนะนำว่าให้ทำเป็น desktop application (Windows Form หรือ Console app) จะเจอปัญหาน้อยกว่าเอาไปทำเป็น web application

ใช้ class WebClient ให้ไปดึงข้อความมาจากเว็บบอร์ดเรื่อยๆก็ได้ครับ

ob
ob
6/28/2010 9:31:50 AM #

ผมลองใช้แล้วมีบางประโยคที่ตัดผิดอยู่ครับ เดี๋ยวเอาให้ดู แล้วอยากทราบว่าเราสามารถเพิ่มคำศัพท์ที่ใช้เปรียบเทียบในการตัดคำได้หรือไม่ครับ

Noomkingkong
Noomkingkong
7/8/2010 3:38:38 PM #

ผมอยากเอาไปพัฒนาต่ออ่ะครับ


อยากขอ ซอสโค้ด ต้องติดต่อคุรยยังไง ครับ  บอกทีครัย


นศ วิทยาการคอม ฯ อิอิ

ob
ob
8/26/2010 2:09:35 PM #

ช่วยด้วยครับ พอดีผมเอา ICU4NET ไปใช้แล้ว Compile เรียบร้อยแล้ว ลอง Install เครื่องตัวเองได้ ไป Install เครื่องอื่นที่ลงโปรแกรม Visual Studio.Net 2008 เมื่อ Install แล้ว ก็ลงได้ แต่พอผมเอาไปลงเครื่องที่ ไม่มี Visual Studio.Net 2008 กลับ เกิด Error ดังนี้ ครับ รบกวนหน่อยนะครับ

[เอา error message ออกไปแล้วนะครับ มันแอบยาว /m3rlinez]

ผม Add DLL เข้าไปแล้ว แต่ยัง Error อยู่
ขอบคุณครับ

ob
ob
8/26/2010 2:20:08 PM #

ช่วยบอกด้วยครับว่าผมจะต้องลง Driver อะไรของ VS.NET2008 เพิ่มบ้าง โดยไม่ต้องลงโปรแกรม VS.NET 2008 ช่วยด้วยครับ

ob
ob
8/26/2010 2:38:36 PM #

4/5/2553 15:22:31 #
คุณ ob ใช้งานโปรแกรมตัวอย่างที่ติดไปได้รึเปล่าครับ ?
-----------------------------------------------------------

Error เหมือนกันครับ

m3rlinez
m3rlinez
8/26/2010 11:22:15 PM #

อ่านคร่าวๆแล้วดูเหมือน copy DLLs ไปไม่ครบ ตอนเอาไป deploy ได้ copy DLL ตัวไหนไปบ้างครับ ?

ปกติโปรแกรมตัวอย่างที่ดาวน์โหลดไป ถ้าเครื่องมี .NET Framework 3.5 ลงไว้แล้ว ควรจะรันได้เลยหลังแตก zip ถ้าไม่ได้ลอง copy log แบบเดียวกันจากโปรแกรมตัวอย่างมาให้ดูหน่อยละกันครับ

ob
ob
8/27/2010 11:57:19 AM #

ลง framwork 3.5 แล้ว ผม Add refference และ copy dll ไป deploy ตามที่ได้ตาม Readme นะครับ

ICU4NETExtension.dll
ICU4NET.dll
icudt42.dll
icuin42.dll
icuio42.dll
icule42.dll
iculx42.dll
icutu41.dll
icuuc42.dll

ปัญหาอย่างที่บอกครับ ว่าต้องมี VS.NET 2008 ถึงจะได้ครับ ถ้าไม่มีก็ Error แบบนั้นครับ

ob
ob
8/27/2010 12:05:40 PM #

Log ที่เกิด Error เมื่อ Run Sample File  โดยที่ไม่ได้ลง VS.NET 2008 ครับ

[เอา error message ออกไปแล้วนะครับ มันแอบยาว /m3rlinez]

m3rlinez
m3rlinez
8/27/2010 10:32:06 PM #

@ob ขอบคุณสำหรับรายละเอียดเพิ่มเติมนะครับ ผมลองดูแล้วปรากฎว่าเป็นเหมือนกัน - -' สั้นๆคือมันเกิดจาก ICU4NET.dll ที่แจกจ่ายไปมัน build มาแบบ Debug แล้วมัน depends on debug version ของ VC++ Run-time อันนี้ตอนแรกก็หาไม่เจอเหมือนกันเพราะทุกเครื่องที่ใช้ดันลง VS2008 ไว้หมด

เร็วๆนี้จะเอาเวอร์ชันที่ build แบบ Release มาให้ใหม่ คิดว่าหลังจากเปลี่ยนเป็นเวอร์ชันนี้แล้ว ตอนเอาไปลงที่เครื่องที่ไม่มี VS2008 ก็แค่ลง VC++ 2008 Run-time ไปด้วย (~2 MB) ก็จะรันได้ตามปกติแล้ว

ผมทำ ticket ไว้ที่ code.google.com/p/icu4net/issues/detail?id=2 ไปติดตาม update ได้

m3rlinez
m3rlinez
8/27/2010 11:00:18 PM #

@ob เวอร์ชัน 0.0.3 ออกแล้วนะครับ เอาไปลองดู http://code.google.com/p/icu4net/downloads/list

ob
ob
8/30/2010 11:15:50 AM #

ใช้ได้แล้วครับ เยี่ยมครับ ขอบคุณมากครับ
Cheer

rangsarn
rangsarn
12/9/2010 3:33:14 PM #

ฉัน|มาร|อก|ราบ|พระสงฆ์
ฉัน|มา|รอก|ราบ|พระสงฆ์
ฉัน|มา|รอ|กราบ|พระสงฆ์

เรือ|โคลง|เพราะ|โคลง|เรือ
เรือ|โคลง|เพราะ|โค|ลง|เรือ
เรือ|โค|ลง|เพราะ|โคลง|เรือ
เรือ|โค|ลง|เพราะ|โค|ลง|เรือ

คน|ตาก|ลม|นอน|ตาก|ลม
คน|ตาก|ลม|นอน|ตา|กลม
คน|ตา|กลม|นอน|ตาก|ลม
คน|ตา|กลม|นอน|ตา|กลม
คน|ตา|กล|มน|อน|ตาก|ลม
คน|ตา|กล|มน|อน|ตา|กลม

จะเกิดอะไรขึ้นเมื่อโปรแกรมแบ่งคำผิด ?

สุระพล
สุระพล
8/1/2011 11:08:36 PM #

ขอรบกวนหน่อยครับ ผมใช้ ICU4NET Run บน VS2008 Run ได้แต่ Run บน IIS มัน Error ครับ ผมใช้ IIS 6 ครับ

สุระพล
สุระพล
8/2/2011 3:15:28 AM #

รบกวนหน่อยครับ คือผมใช้ ICU4NET Run บน VS2008 มัน Run ได้ไม่มีปัญหา แต่พอ Run ผ่าน IIS 6 มัน Run ไม่ได้มัน ฟ้องแบบนี้ครับ มันเกิดจากอะไรครับ แล้ววิธีแก้ไขทำอย่างไรครับ

Server Error in '/' Application.
--------------------------------------------------------------------------------

Could not load file or assembly 'ICU4NET' or one of its dependencies. An attempt was made to load a program with an incorrect format.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.

Exception Details: System.BadImageFormatException: Could not load file or assembly 'ICU4NET' or one of its dependencies. An attempt was made to load a program with an incorrect format.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.  

Assembly Load Trace: The following information can be helpful to determine why the assembly 'ICU4NET' could not be loaded.


WRN: Assembly binding logging is turned OFF.
To enable assembly bind failure logging, set the registry value [HKLM\Software\Microsoft\Fusion!EnableLog] (DWORD) to 1.
Note: There is some performance penalty associated with assembly bind failure logging.
To turn this feature off, remove the registry value [HKLM\Software\Microsoft\Fusion!EnableLog].



Stack Trace:


[BadImageFormatException: Could not load file or assembly 'ICU4NET' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
   System.Reflection.RuntimeAssembly._nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, RuntimeAssembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection, Boolean suppressSecurityChecks) +0
   System.Reflection.RuntimeAssembly.InternalLoadAssemblyName(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection, Boolean suppressSecurityChecks) +567
   System.Reflection.RuntimeAssembly.InternalLoad(String assemblyString, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection) +192
   System.Reflection.Assembly.Load(String assemblyString) +35
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +123

[ConfigurationErrorsException: Could not load file or assembly 'ICU4NET' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
   System.Web.Configuration.CompilationSection.LoadAssemblyHelper(String assemblyName, Boolean starDirective) +11479520
   System.Web.Configuration.CompilationSection.LoadAllAssembliesFromAppDomainBinDirectory() +484
   System.Web.Configuration.AssemblyInfo.get_AssemblyInternal() +79
   System.Web.Compilation.BuildManager.GetReferencedAssemblies(CompilationSection compConfig) +334
   System.Web.Compilation.BuildManager.CallPreStartInitMethods() +280
   System.Web.Hosting.HostingEnvironment.Initialize(ApplicationManager appManager, IApplicationHost appHost, IConfigMapPathFactory configMapPathFactory, HostingEnvironmentParameters hostingParameters, PolicyLevel policyLevel, Exception appDomainCreationException) +1087

[HttpException (0x80004005): Could not load file or assembly 'ICU4NET' or one of its dependencies. An attempt was made to load a program with an incorrect format.]
   System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +11612256
   System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +141
   System.Web.HttpRuntime.ProcessRequestInternal(HttpWorkerRequest wr) +11443374




--------------------------------------------------------------------------------
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1

m3rlinez
m3rlinez
8/2/2011 7:23:20 PM #

@สุระพล อันนี้ใช้ Windows Server เวอร์ชันอะไรอ่ะครับ แล้วเป็น 64-bit หรือ 32-bit? ตัว ICU4NET ตอนนี้มีเฉพาะ 32-bit อ่ะครับ อาจจะต้อง set IIS ตามเว็บนี้ (แต่ผมยังไม่เคยลองนะ) -> www.alexjamesbrown.com/.../

Add comment




biuquote
  • Comment
  • Preview
Loading






Most comments

khimkhim khimkhim
1 comments
weaw weaw
1 comments
domehuhu domehuhu
1 comments

RecentComments

Comment RSS