用于类似 Google 建议的字典






4.90/5 (11投票s)
2005年6月6日
3分钟阅读

58544

1153
创建一个可以像Google Suggest字典一样工作的字典。

引言
当我阅读由Gavi Narra撰写的Google Suggest字典文章时,我发现那个字典是HTML纯文本格式的,需要将其转换为数据库表。
这些数据来自一个免费的在线字典(一个公共领域的英语单词列表字典,基于《古登堡计划》的《韦氏大学词典》的公共领域部分,该部分又基于1913年的美国《韦氏大学词典》。你可以在这里下载)。
我构建了一个小型VB.NET应用程序,可以将这些HTML文件及其中的数据转换为有意义的数据库表。
使用代码
转换成功需要两个步骤
- 将HTML文件转换为字符分隔值。
- 处理分隔值以生成INSERT INTO语句。
我使用MS Access数据库来保存结果,但我认为使用MS SQL在转换过程中以及作为字典都是更合适的。
第一步(创建基础)
基础是将HTML纯文本转换为分隔值(CSV)的结果。HTML文件包含纯文本字典,如下所示
Islam (n.) The religion of the Mohammedans; Mohammedanism; 
Islamism. Their formula of faith is: There is no God but Allah, 
and Mohammed is his prophet.
必须以某种方式将其转换为可读格式并插入数据库。最好的方法是使用字符分隔值,如下所示
Islam@(n.)@The religion of the Mohammedans; Mohammedanism; 
Islamism. Their formula of faith is: There is no God but Allah, 
and Mohammed is his prophet.
其中@是用作字段分隔符的字符。数据库插入后的结果将是
| Dict | |
| 单词 | Islam | 
| 类型 | (n.) | 
| 平均 | 伊斯兰教;穆斯林宗教;伊斯兰主义。他们的信仰格言是:万物非主,唯有安拉;穆罕默德是安拉的使者。 | 
该项目将运行的流程是 HTML ----第一步----> CSV ----第二步----> 数据库。
从HTML到CSV的代码转换位于按钮的Click事件中。HTML文件包含一些不需要的标签,可以用作转换的提示。txtpath2文本框是HTML文件路径,而txtpathtarget文本框是目标文件路径,可以是任何扩展名。使用IO.StreamReader打开txtpath2中指定的名称文件,然后用@字符替换一些标签,然后将文件保存在另一个位置,这是此步骤的核心操作。
Private Sub Button2_Click(ByVal sender As System.Object, _
         ByVal e As System.EventArgs) Handles Button2.Click
  progbar2.Value = 0
  Dim myfile = New IO.StreamReader(txtpath2.Text)
  Try
    '---Proceesing the file that contain delimited contents
    Dim Line As String
    Line = myfile.Readtoend
    '----Remove unwanted tags
    Line = Line.Replace("<P>", "")
    progbar2.Value += 1
    Line = Line.Replace("</P>", "")
    progbar2.Value += 1
    Line = Line.Replace("<B>", "")
    progbar2.Value += 1
    Line = Line.Replace(" (<I></I>) ", "@")
    progbar2.Value += 1
    Line = Line.Replace("</B>", "@")
    progbar2.Value += 1
    Line = Line.Replace(" (<I>", "")
    progbar2.Value += 1
    Line = Line.Replace("</I>) ", "@")
    progbar2.Value += 1
    Dim myfileSave As New IO.StreamWriter(txtpathtarget.Text, True)
    myfileSave.Write(Line)
    myfileSave.Close()
    progbar2.Value += 1
    MessageBox.Show("Substrate completed successfully", _
                    "Dict Maker")
  Catch ex As IO.IOException
    MessageBox.Show("Error: " & ex.Message, "Critical error", _
                    MessageBoxButtons.OK, MessageBoxIcon.Error)
  Catch ex As Exception
    MessageBox.Show("Error: " & ex.Message, "Critical error", _
                    MessageBoxButtons.OK, MessageBoxIcon.Error)
  Finally
    myfile.Close()
  End Try
End Sub
正如你所看到的,应该创建一个包含CSV的目标文件。这个文件将在第二步中用于生成INSERT INTO语句。
第二步(绑定到酶)
一旦你完成了将HTML文件转换为CSV文件,你就可以进一步从CSV文件中生成所需的INSERT INTO语句。在此步骤中,你将指定由第一步制作的CSV文件。
此步骤包括打开数据库连接,生成SQL命令,使用IO.StreamReader逐行处理CSV,并执行命令。txtpath文本框包含CSV文件路径。我使用了split函数,该函数识别字符串中由数组(@)中指定的一个或多个字符分隔的子字符串,然后将子字符串放入一个String数组。
返回的数组的上限为2(3个元素),分别为0-1-2。数组元素分别是单词、类型和含义。将为每个值生成一个SQL语句。由于我使用的是MS Access数据库,命令需要逐个执行。如果你将数据库更改为MS SQL,你可以生成INSERT INTO语句,然后一次性执行它们,因为MS SQL服务器支持批处理或多查询。这将提高应用程序的性能。
转换过程附带进度条,其最大值由CalculateEstimate函数提供,该函数将循环遍历CSV文件以计算将要处理的行数。
注意:不要忘记在连接字符串中指定数据源路径,否则应用程序将无法工作。
Private Sub Button1_Click(ByVal sender As System.Object, _
            ByVal e As System.EventArgs) Handles Button1.Click
  ProgBar.Value = 0
  If txtpath.Text = "" Then Exit Sub
  MsgBox(txtpath.Text)
  '-----Open the connection
  Dim con As New OleDb.OleDbConnection
  Dim com As New OleDb.OleDbCommand
  '------
  con.ConnectionString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ 
                         "Data Source=d:\vbprograms\dictmaker\dict.mdb"
  '----calculate estimates and set the progress bar
  ProgBar.Maximum = CalculateEstimate(txtpath.Text)
  '----
  Dim myfile = New IO.StreamReader(txtpath.Text)
  Try
    '--open the database
    con.Open()
    '---Proceesing the file that contain delimited contents
    Dim Line As String
    Dim AfterSep() As String
    '--------------------Ignore the first 9 lines
    For t As Integer = 1 To 9
      myfile.ReadLine()
    Next t
    '--------------------
    While myfile.Peek > -1
      Application.DoEvents()
      Line = myfile.ReadLine()
      If Line = "</BODY>" Then Exit While
      '----If the carriage return, request next line
      If Line = "" Then Line = myfile.ReadLine()
      AfterSep = Line.Split("@"c)
      '----Build the command and executeit
      com.Connection = con
      com.CommandText = _
         "INSERT INTO dict (word,type,mean) VALUES (?,?,?)"
      com.Parameters.Clear()
      com.Parameters.Add("?", AfterSep(0))
      com.Parameters.Add("?", AfterSep(1))
      com.Parameters.Add("?", AfterSep(2))
      com.ExecuteNonQuery()
      '----Set value progress
      ' If ProgBar.Value = 5136 Then Stop
      ProgBar.Value += 1
      lblprocessed.Text = "Line(s) processed : " & ProgBar.Value
    End While
    MessageBox.Show("Conversion completed successfully", "Dict Maker")
  Catch ex As OleDb.OleDbException
    MessageBox.Show("Error: " & ex.Message, _
      "Critical error", MessageBoxButtons.OK, _
      MessageBoxIcon.Error)
  Catch ex As IO.IOException
    MessageBox.Show("Error: " & ex.Message, _
      "Critical error", MessageBoxButtons.OK, MessageBoxIcon.Error)
  Catch ex As Exception
    MessageBox.Show("Error: " & ex.Message, _
      "Critical error", MessageBoxButtons.OK, MessageBoxIcon.Error)
  Finally
    con.Close()
    myfile.Close()
  End Try
End Sub 
计算将要处理的行数
Function CalculateEstimate(ByVal path As String) As Integer
  Dim estimate As New IO.StreamReader(path)
  Dim NumOfLines As Integer
  While estimate.Peek > -1
    estimate.ReadLine()
    NumOfLines += 1
  End While
  estimate.Close()
  lblTotalLines.Text = "Total Line(s): " & NumOfLines - 11
  Return NumOfLines
End Function
最后
尽管VS2005 ASP 2.0已经覆盖了Gavi Narra所写的想法(HttpXmlRequest),但他的工作确实很棒,我希望我的工作能起到补充作用。
此致。
