{"id":35673,"date":"2005-05-10T09:03:55","date_gmt":"2005-05-10T09:03:55","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/oldnewthing\/2005\/05\/10\/loading-the-dictionary-part-1-starting-point\/"},"modified":"2005-05-10T09:03:55","modified_gmt":"2005-05-10T09:03:55","slug":"loading-the-dictionary-part-1-starting-point","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20050510-55\/?p=35673","title":{"rendered":"Loading the dictionary, part 1:  Starting point"},"content":{"rendered":"<p>\nThe first thing we&#8217;ll need to do in our little dictionary program\nis to load the dictionary into memory.  The format of the dictionary\nfile is as a plain text file, each line of which is of the form\n<\/p>\n<pre>\nChinese [pinyin] \/English 1\/English 2\/...\/\n&#x8209;&#x4F8B; [ju3 li4] \/to give an example\/\n<\/pre>\n<p>\nSince it was the Big5 dictionary we downloaded,\nthe Chinese characters are in Big5 format,\nknown to Windows as code page 950.\nOur program will be Unicode, so we&#8217;ll have to convert it as we load\nthe dictionary.  Yes, I could&#8217;ve used the Unicode version of the\ndictionary, but it so happens that when I set out to write this program,\n<a HREF=\"http:\/\/ftp.cc.monash.edu.au\/pub\/nihongo\/cedict.html\">\nthere was no Unicode version available<\/a>.\nFortunately, this oversight opened up the opportunity to illustrate\nsome other programming decisions and techniques.\n<\/p>\n<p>\nThe first stage in our series of exercises will be loading the dictionary\ninto memory.\n<\/p>\n<pre>\n<a href=\"http:\/\/blogs.msdn.com\/oldnewthing\/archive\/2004\/02\/12\/71851.aspx\">#define UNICODE\n#define _UNICODE<\/a>\n#include &lt;windows.h&gt;\n#include &lt;string&gt;\n#include &lt;fstream&gt;\n#include &lt;iostream&gt; \/\/ for cin\/cout\n#include &lt;vector&gt;\nusing std::string;\nusing std::wstring;\nusing std::vector;\nstruct DictionaryEntry\n{\n bool Parse(const wstring&amp; line);\n wstring trad;\n wstring simp;\n wstring pinyin;\n wstring english;\n};\nbool DictionaryEntry::Parse(const wstring&amp; line)\n{\n    wstring::size_type start = 0;\n    wstring::size_type end = line.find(L' ', start);\n    if (end == wstring::npos) return false;\n    trad.assign(line, start, end);\n    start = line.find(L'[', end);\n    if (start == wstring::npos) return false;\n    end = line.find(L']', ++start);\n    if (end == wstring::npos) return false;\n    pinyin.assign(line, start, end - start);\n    start = line.find(L'\/', end);\n    if (start == wstring::npos) return false;\n    start++;\n    end = line.rfind(L'\/');\n    if (end == wstring::npos) return false;\n    if (end &lt;= start) return false;\n    english.assign(line, start, end-start);\n    return true;\n}\nclass Dictionary\n{\npublic:\n Dictionary();\n int Length() { return v.size(); }\n const DictionaryEntry&amp; Item(int i) { return v[i]; }\nprivate:\n vector&lt;DictionaryEntry&gt; v;\n};\nDictionary::Dictionary()\n{\n std::wifstream src;\n src.imbue(std::locale(\".950\"));\n src.open(\"cedict.b5\");\n wstring s;\n while (getline(src, s)) {\n  if (s.length() &gt; 0 &amp;&amp; s[0] != L'#') {\n   DictionaryEntry de;\n   if (de.Parse(s)) {\n    v.push_back(de);\n   }\n  }\n }\n}\nint __cdecl main(int argc, const char* argv[])\n{\n DWORD dw = GetTickCount();\n {\n  Dictionary dict;\n  std::cout &lt;&lt; dict.Length() &lt;&lt; std::endl;\n  std::cout &lt;&lt; GetTickCount() - dw &lt;&lt; std::endl;\n }\n std::cout &lt;&lt; GetTickCount() - dw &lt;&lt; std::endl;\n return 0;\n}\n<\/pre>\n<p>\nOur dictionary is just a list of words with their English definitions.\nThe Chinese words are written in three forms\n(traditional Chinese,\nsimplified Chinese, and\nPinyin romanization).\nFor those who are curious, there are two writing systems\nfor the Mandarin Chinese language and two phonetic systems.\nWhich one a particular Mandarin-speaking population follows depends\non whether they fell under the influence of China&#8217;s\nlanguage reform of 1956.\nTraditional Chinese characters and the Bopomo\nphonetic system\n(also called Bopomofo)\nare used on Taiwan; simplified Chinese characters\nand the Pinyin system are used in China.\nConverting Pinyin to Bopomo isn&#8217;t interesting,\nso I&#8217;ve removed that part from the program I&#8217;m presenting here.\n<\/p>\n<p>(The schism in the spelling of the English language follows a similar\npattern.\nUnder the leadership of Noah Webster,\nthe United States underwent its own spelling reform,\nbut countries which were under the influence of the British crown\nretained the traditional spellings.\n<a HREF=\"http:\/\/www.goethe.de\/z\/50\/reform\/\">\nSpelling reform continues in other languages even today<\/a>,\nand the subject is almost always highly contentious,\nwith traditionalists and reformists pitted against each other\nin a battle over a language&#8217;s&mdash;and by proxy,\na culture&#8217;s&mdash;identity.)<\/p>\n<p>\nThe program itself is fairly straightforward.\nIt creates a Unicode file stream <code>wifstream<\/code>\nand &#8220;imbues&#8221; it with code page 950 (Big5).\nThis instructs the runtime to interpret the bytes of the file\ninterpreted in the specified code page.\nWe read strings out of the file, ignore the comments,\nand parse the rest, appending them to our <code>vector<\/code>\nof dictionary entries.\n<\/p>\n<p>\nParsing the line consists of finding the spaces, brackets,\nand slashes, and splitting the line into the traditional Chinese,\nPinyin, and English components.  (We&#8217;ll deal with simplified\nChinese later.)\n<\/p>\n<p>\nWhen I run this program on my machine, the dictionary loads in 2080ms\n(or 2140ms if you include the time to run the destructor).\nThis is an unacceptably long startup time, so the first order\nof business is to make startup faster.  That will be the focus of\nthis stage.\n<\/p>\n<p>\nNotice that as a sanity check, I print the total number of words in the\ndictionary.  The number should match the number of lines in the\n<code>cedict.b5<\/code> file (minus the one comment line).\nIf not, then I know that something went wrong.\n<strong>This is an important sanity check<\/strong>:\nYou might make a performance optimization that looks great\nwhen you run it past a stopwatch,\nonly to discover that your &#8220;optimization&#8221; actually introduced a\nbug.  For example, one of my attempted optimizations of this program\nresulted in a phenomenal tenfold speedup,\nbut only because of a bug that caused it to think it was finished\nwhen it had in reality processed only 10% of the dictionary!\n<\/p>\n<p>\nAs my colleague\n<a HREF=\"http:\/\/blogs.msdn.com\/ricom\">Rico Mariani<\/a> is fond of saying,\n&#8220;It&#8217;s easy to make it fast if it doesn&#8217;t have to work!&#8221;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The first thing we&#8217;ll need to do in our little dictionary program is to load the dictionary into memory. The format of the dictionary file is as a plain text file, each line of which is of the form Chinese [pinyin] \/English 1\/English 2\/&#8230;\/ &#x8209;&#x4F8B; [ju3 li4] \/to give an example\/ Since it was the [&hellip;]<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-35673","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>The first thing we&#8217;ll need to do in our little dictionary program is to load the dictionary into memory. The format of the dictionary file is as a plain text file, each line of which is of the form Chinese [pinyin] \/English 1\/English 2\/&#8230;\/ &#x8209;&#x4F8B; [ju3 li4] \/to give an example\/ Since it was the [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/35673","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=35673"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/35673\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=35673"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=35673"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=35673"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}