熱點推薦:
您现在的位置: 電腦知識網 >> 編程 >> Java編程 >> Java核心技術 >> 正文

JAVA版StarDict星際譯王簡單實現

2022-06-13   來源: Java核心技術 

  由胡正開發的星際譯王是Linux平台上很強大的一個開源的翻譯軟件(也有Windows版本的)支持多種詞庫多種語言版本尤其詞庫設計比較合理之前看到一篇博文《星際譯王詞庫應用自制英漢詞典》中用簡短的程序就實現了詞典的基本功能不過那個是Linux 下的C/C++版本的於是決定參考移植一個JAVA版本
  import javaioByteArrayOutputStream;
  import javaioIOException;
  import javaioInputStream;
  import javaio*;
  /**
  * {@docRoot}
  * Java版詞典測試版可以在控制台下輸入要查詢的單詞回車後會給出單詞在詞典中的釋義
  * 詞典采用星際譯王的詞典本程序主要針對英漢詞典
  *
  * @author menglongbor
  * @updateDate
  * @version v
  *
  * 相關參考鏈接
  * l
  * _zhu_xiang/item/fbeeeee
  *
  *
  *
  * /downloads/list
  *
  */
  public class testdict
  {
  final static intMAX_WORD= ;// 最長輸入單詞字符數
  final static intMAX_KEYS= ;// 個字母+開頭的後綴
  final static intSIZEINT= ;
  final static StringKEY[]= {// 個字母索引+開頭的後綴不區分大小寫
  A b c d e f
  g h i j k l m n o p q r s
  t u v w x y z };
  public static InputStreamisidx= null;// 讀取idx文件時所要的流
  public static InputStreamisdict= null;// 讀取dict文件時所要的流
  public static longSTREAM_LOCAL= ;// 記錄單詞索引在文件流中的位置
  public static StringidxfileString= oxfordgbidx;// idx文件路徑
  public static StringdictfileString= oxfordgbdict;// dict文件路徑
  /**
  * 從idx文件中獲取當前目標單詞
  * @param word_buf 保存的是c/c++字符串數組轉換為JAVA字符串
  * @param data_poffset 用來保存單詞的data偏移位置信息
  * @param data_plength 用來保存單詞的data長度信息
  * @param len
  * @return
  */
  public static boolean get_word(String[] word_buf int[] data_poffset
  int[] data_plength int[] len)
  {
  // int len = ;
  boolean flag = true;
  len[] = ;
  int index = ;
  byte wd[] = new byte[MAX_WORD];
  int value = ;
  try
  {
  // 讀取單詞對每個字母開頭的單詞都進行搜索最多考慮個字符的單詞
  // 讀到單詞結束符\時賦值表達式的值就不滿足while條件而退出
  while (true)
  {
  index = isidxread()
  STREAM_LOCAL++;// 每讀取一次位置標識加一以記錄下單詞在文件流中的起始位置
  if (index ==
  {
  // isidxreset()
  flag = false;
  break;
  }
  if ((index != ) && (len[] < MAX_WORD))
  {
  wd[len[]] = (byte) index;// 將int轉換為byte
  len[]++;
  } else
  {
  break;
  }
  }
  // 轉換為JAVA字符串
  // 此處不用再需要像c/c++那樣去掉了最後那個結束符了
  byte wd[] = new byte[len[]];
  for (int i = ; i < len[]; i++)
  {
  wd[i] = wd[i];
  }
  word_buf[] = new String(wd
  // Systemoutprintln(get_word:+word_buf[]+ len:+len[])
  // wd = null;// 釋放內存
  // wd = null;
  // 讀取偏移量值
  for (int i = ; i < SIZEINT; i++)
  {
  // 將個byte轉換為int
  int shift = ( i) * ;
  index = isidxread()
  STREAM_LOCAL++;// 每讀取一次位置標識加一以記錄下單詞在文件流中的起始位置
  if (index ==
  {
  // isidxreset()
  flag = false;
  return flag;
  }
  value += (index & xFF) 《 shift;
  }
  data_poffset[] = value;
  // 讀取區塊大小值
  value = ;
  for (int i = ; i < SIZEINT; i++)
  {
  // 將個byte轉換為int
  int shift = ( i) * ;
  index = isidxread()
  STREAM_LOCAL++;// 每讀取一次位置標識加一以記錄下單詞在文件流中的起始位置
  if (index ==
  {
  // isidxreset()
  flag = false;
  return flag;
  }
  value += (index & xFF) 《 shift;
  }
  data_plength[] = value;
  }
  catch (Exception e)
  {
  Systemoutprintln(idx file read error!
  }
  // Systemoutprintln(Now local is:+STREAM_LOCAL)
  // 得到單詞字符長度
  return flag;
  }
  /**
  * 通過偏移位置offset和長度length 來從dict文件中獲取data內容UTF編碼的字符
  * @param offset 要讀取的內容的起始偏移為字節數


 
  * @param length 要讀取的內容的數據塊大小為字節數
  * @return 字節數組的data int
  */
  public static byte[] get_data(int[] offset int[] length)
  {
  long oft = offset[];
  long len = length[];
  long skip;
  byte data_buf[] = new byte[length[]];
  Systemoutprintln(This words + offset: + offset[] + len:
  + length[])
  try
  {
  isdictreset()
  long valuedata = isdictavailable()
  if (valuedata < oft + len)
  {
  Systemoutprintln(No so much value data! + valuedata)
  }
  // skip=isdictskip(oft)
  skip = skipBytesFromStream(isdict oft)
  if (skip != oft)
  {
  Systemoutprintln(Skip + skip + dict file error!
  }
  if (isdictread(data_buf) ==
  {
  Systemoutprintln(Arrive at the end of file!
  }
  // // Unicode
  // StringBuffer sb = new StringBuffer()
  //
  // int size =isdictread(data_buf)
  //
  // for (int j = ; j < size;)
  // {
  //
  // int l = data_buf[j++];
  //
  // int h = data_buf[j++];
  //
  // char c = (char) ((l & xff) | ((h 《 ) & xff))
  //
  // sbappend(c)
  //
  // }
  //
  // // return sbtoString()
  }
  catch (Exception e)
  {
  data_buf = null;
  Systemoutprintln(dict file read error!
  eprintStackTrace()
  }
  if (data_buf == null)
  {
  return null;
  }
  return data_buf;
  }
  /**
  * utf解碼 參考自 用法
  * 假如 newContent 為UTF編碼的字符串 byte[] b = newContentgetBytes() newContent =
  * URLEncoderUTFDecode( b blength )
  * @param in 要進行解碼的UTF編碼的字節數組
  * @param offset
  * @param length
  * @return
  */
  public static String UTFDecode(byte in[] int offset int length)
  {
  StringBuffer buff = new StringBuffer()
  int max = offset + length;
  for (int i = offset; i < max; i++)
  {
  char c = ;
  if ((in[i] & x) ==
  {
  c = (char) in[i];
  } else if ((in[i] & xe) == xc) //
  {
  c |= ((in[i] & xf) 《 //
  i++;
  c |= ((in[i] & xf) 《 //
  } else if ((in[i] & xf) == xe) //
  {
  c |= ((in[i] & xf) 《 //
  i++;
  c |= ((in[i] & xf) 《 //
  i++;
  c |= ((in[i] & xf) 《 //
  } else if ((in[i] & xf) == xf) //
  {
  c |= ((in[i] & x) 《 // (move not
  i++;
  c |= ((in[i] & xf) 《 //
  i++;
  c |= ((in[i] & xf) 《 //
  i++;
  c |= ((in[i] & xf) 《 //
  } else
  {
  c = ;
  }
  buffappend(c)
  }
  return bufftoString()
  }
  public static byte[] UTFEncode(String str)
  {
  ByteArrayOutputStream bos = new ByteArrayOutputStream()
  try
  {
  int strlen = strlength()
  for (int i = ; i < strlen; i++)
  {
  char t = strcharAt(i)
  int c = ;
  c |= (t & xffff)
  if (c >= && c < x
  {
  boswrite((byte) (c & xff))
  } else if (c > xf && c < x
  {
  boswrite((byte) (((c >>> ) & xf) | xc))
  boswrite((byte) (((c >>> ) & xf) | x))
  } else if (c > xff && c < x
  {
  boswrite((byte) (((c >>> ) & xf) | xe)) // <
  // correction
  // (mb)
  boswrite((byte) (((c >>> ) & xf) | x))
  boswrite((byte) (((c >>> ) & xf) | x))
  } else if (c > xffff && c < xfffff)
  {
  boswrite((byte) (((c >>> ) & x) | xf))
  boswrite((byte) (((c >>> ) & xf) | x))
  boswrite((byte) (((c >>> ) & xf) | x))
  boswrite((byte) (((c >>> ) & xf) | x))
  }
  }
  bosflush()
  }
  catch (Exception e)
  {
  }
  return bostoByteArray()
  }
  /**
  * 將UTF字節數據轉化為Unicode字符串
  *
  * @param utf_data
  *            byte[] UTF編碼字節數組
  * @param len
  *            int 字節數組長度
  * @return String 變換後的Unicode編碼字符串
  */
  public static String UTFUni(byte[] utf_data int len)
  {
  StringBuffer unis = new StringBuffer()
  char unic = ;
  int ptr = ;
  int cntBits = ;
  for ( ptr < len;)
  {
  cntBits = getCntBits(utf_data[ptr])
  if (cntBits ==
  {
  ++ptr;
  continue;
  } else if (cntBits ==
  {
  unic = UTFCUniC(utf_data ptr cntBits)
  ++ptr;
  } else
  {
  unic = UTFCUniC(utf_data ptr cntBits)
  ptr += cntBits;
  }
  unisappend(unic)
  }
  return unistoString()
  }
  /**
  * 將指定的UTF字節組合成一個Unicode編碼字符
  * @param utf byte[] UTF字節數組
  * @param sptr int 編碼字節起始位置
  * @param cntBits int 編碼字節數
  * @return char 變換後的Unicode字符
  */
  public static char UTFCUniC(byte[] utf int sptr int cntBits)
  {
  /*
  * Unicode <> UTF U UF: xxxxxxx U
  * UFF: xxxxx xxxxxx U UFFFF: xxxx
  * xxxxxx xxxxxx U UFFFFF: xxx xxxxxx xxxxxx
  * xxxxxx U UFFFFFF: xx xxxxxx xxxxxx xxxxxx
  * xxxxxx U UFFFFFFF: x xxxxxx xxxxxx xxxxxx
  * xxxxxx xxxxxx
  */
  int uniC = ; // represent the unicode char
  byte firstByte = utf[sptr];
  int ptr = ; // pointer ~
  // resolve single byte UTF encoding char
  if (cntBits ==
  return (char) firstByte;
  // resolve the first byte
  firstByte &= ( 《 ( cntBits)) ;
  // resolve multiple bytes UTF encoding char(except the first byte)
  for (int i = sptr + cntBits ; i > sptr; i)
  {
  byte utfb = utf[i];
  uniC |= (utfb & xf) 《 ptr;
  ptr += ;
  }
  uniC |= firstByte 《 ptr;
  return (char) uniC;
  }
  /**


 
  * 根據給定字節計算UTF編碼的一個字符所占字節數UTF規則定義字節標記只能為~
  * @param b
  * @return
  */
  private static int getCntBits(byte b)
  {
  int cnt = ;
  if (b ==
  return ;
  for (int i = ; i >= ; i)
  {
  if (((b 》 i) & x) ==
  ++cnt;
  else
  break;
  }
  return (cnt > || cnt == )  : cnt;
  }
  /**
  * 顯示data內容
  * @param data_buf UTF的單詞釋義數組
  * @param data_length UTF的單詞釋義數組長度
  */
  public static void display_data(byte[] data_buf int data_length[])
  {
  // 將UTFbyte字節數組轉為當前環境字符並顯示
  // String tempString = UTFDecode(data_buf data_length[])
  String tempString = UTFUni(data_buf data_length[])
  // String tempString = new String(data_buf)
  data_buf = null;
  Systemoutprintln(tempString)
  }
  /**
  * 從idx文件中搜索由word指定的單詞並保存相應的偏移和長度信息
  * @param word
  * @param data_poffset
  * @param data_plength
  * @return 是否搜索成功
  */
  public static boolean search_word(String word int[] data_poffset
  int[] data_plength)
  {
  String wd[] = new String[];
  boolean temp = false;
  int len[] = new int[];
  // 從idx文件中獲取當前目標單詞
  // for (get_word(wd data_poffset data_plength) end; get_word(wd
  // data_poffset data_plength))
  // {
  while (get_word(wd data_poffset data_plength len))
  {
  // Systemoutprintln(compared_word:+wd[])
  // if (wd[pareToIgnoreCase(word) == ) //
  // 比較字符串s和s但不區分字母的大小寫
  if (strsEqualsIgnoreCase(wd[] word) ==
  {
  Systemoutprintln(compared_word: + word + + wd[])
  temp = true;
  break;
  }
  }
  return temp;
  }
  /**
  * 從標准輸入獲取待查詢的單詞控制台下為GBK字符字典索引中的英文單詞字母也是如此
  * @param max_len
  * @param count
  * @return
  */
  public static String get_input(int max_len int[] count)
  {
  byte input_buf[] = new byte[max_len];
  count[] = ;
  String tempString[] = new String[];
  try
  {
  count[] = Systeminread(input_buf) ;// 返回實際讀取到的字符數減去個控制字符
  byte temp_buf[] = new byte[count[]];
  for (int i = ; i < count[]; i++)
  {
  temp_buf[i] = input_buf[i];
  }
  tempString[] = new String(temp_buf)
  }
  catch (Exception e)
  {
  Systemoutprintln(Input error!
  }
  Systemoutprintln(Your input is: + tempString[])
  return tempString[];
  }
  /**
  * 從標准輸入獲取待查詢的單詞控制台下為GBK字符字典索引中的英文單詞字母也是如此
  * @param input_buf
  * @param count
  * @return
  */
  public static byte[] get_input(byte[] input_buf int[] count)
  {
  try
  {
  count[] = Systeminread(input_buf) ;// 返回實際讀取到的字符數減去個控制字符
  }
  catch (Exception e)
  {
  input_buf = null;
  Systemoutprintln(Input error!
  }
  return input_buf;
  }
  /**
  * 緩存KEYS在idx中的偏移信息以便加快search_word的搜索速度
  * @param idx_cache 保存每個單字母單詞對應的起始位置
  * @return
  */
  public static void cache_idx(long[] idx_cache)
  {
  int i;
  long[] p = idx_cache;
  int unused[] = new int[];
  int unused[] = new int[];
  try
  {
  // 將文件內部的位置指針重新指向一個流(數據流/文件)的開頭返回FILE指針當前位置
  // 然後重新遍歷整個文件搜尋下一個字母開頭的單詞
  isidxreset()
  STREAM_LOCAL = ;
  for (i = ; i < MAX_KEYS; i++)
  {
  // Systemoutprintln(Start search_word: + KEY[i])
  if (search_word(KEY[i] unused unused))// 從idx文件中搜索由word指定的單詞並保存相應的偏移和長度信息
  {
  p[i] = STREAM_LOCAL; // 返回當前文件位置
  // String tempString = LongtoString(STREAM_LOCAL)
  // Systemoutprintln(KEY[i] + s local is: + tempString)
  Systemoutprintln(KEY[i] + s local is: + STREAM_LOCAL
  + offset: + unused[] + length: + unused[])
  } else
  p[i] = ;
  }
  // isidxreset()
  }
  catch (Exception e)
  {
  // TODO: handle exception
  }
  }
  /**
  * 定位由word指定的單詞在idx文件中的大概偏移位置
  * @param word
  * @param idx_cache
  * @return
  */
  public static long locate_idx(String word long[] idx_cache)
  {
  int i = ;
  int pre = ;
  String tempString = wordtoLowerCase()
  while (i < MAX_KEYS && KEY[i]charAt() < tempStringcharAt())
  {
  pre = i;
  ++i;
  }
  if (tempStringcharAt() ==
  {
  pre = ;
  }
  Systemoutprintln(Now words locate is: + idx_cache[pre])
  return idx_cache[pre];
  }
  /**
  * 主要查詢函數
  */
  public static void consult()
  {
  byte data[] = null;// 釋義數據UTF數據
  long idx[] = new long[MAX_KEYS];// 個字母孤立單詞+開頭的後綴對應的索引緩沖
  int offset[] = new int[];
  int length[] = new int[];
  Systemoutprintln(Start cache_idx…!
  try
  {
  Systemoutprintln(Open files…!
  // 讀取字典索引文件
  isidx = new BufferedInputStream(new FileInputStream(
  idxfileString))
  isidxmark(isidxavailable() +
  if (!isidxmarkSupported())
  {
  Systemoutprintln(This stream do not support mark…!
  }
  }
  catch (Exception e)
  {
  Systemoutprintln(Open files error!
  eprintStackTrace()
  }
  cache_idx(idx)// 緩存KEYS在idx中的偏移信息以便加快search_word的搜索速度
  try
  {
  isdict = new BufferedInputStream(new FileInputStream(
  dictfileString))
  isdictmark(isdictavailable() +
  if (!isdictmarkSupported())
  {
  Systemoutprintln(This stream do not support mark…!
  }
  }
  catch (Exception e)
  {
  Systemoutprintln(Open files error!
  eprintStackTrace()
  }
  while (true)
  {
  Systemoutprintln(INPUT A WORD OR PHRASE:
  int count[] = new int[];
  String word = get_input(MAX_WORD count)
  long skips skips;
  if (count[] > )// 從控制台得到輸入單詞字符
  {
  try
  {
  // 從文件開頭跳到單詞大致索引所在位置
  // isidxmark(
  isidxreset()
  skips = locate_idx(word idx)
  // skips = isidxskip(skips
  skips = skipBytesFromStream(isidx skips
  Systemout
  println(skips: + skips + skips: + skips
  }
  catch (Exception e)
  {
  Systemoutprintln(locate_idx run error
  eprintStackTrace()
  }
  if (search_word(word offset length))
  {
  data = get_data(offset length)
  display_data(data length)
  data = null;
  } else
  Systemoutprintln(SORRY + word + CANNOT BE FOUND!\n
  Systemout
  println(\n\n\n
  } else
  break;
  }
  }
  /**
  * 不區分大小寫比較兩個字符串
  *
  * @param s
  * @param s
  * @return
  */
  public static int strsEqualsIgnoreCase(String s String s
  {
  int n = slength() n = slength()
  for (int i = i = ; i < n && i < n; i++ i++)
  {
  char c = scharAt(i
  char c = scharAt(i
  if (c != c
  {
  // 源字符串全部都轉為大寫字符串
  c = CharactertoUpperCase(c
  c = CharactertoUpperCase(c
  if (c != c
  {
  // 源字符串全部都轉為小寫字符串
  c = CharactertoLowerCase(c
  c = CharactertoLowerCase(c
  if (c != c
  {
  return c c;
  }
  }
  }
  }
  return n n;// 如果其中一個或者兩個String都比較完了還沒有同樣的char的話那就return兩個String的長度差距
  }
  /**


 
  * 重寫了Inpustream 中的skip(long n) 方法將數據流中起始的n 個字節跳過
  * 參考
  * @param inputStream
  * @param n
  * @return
  */
  private static long skipBytesFromStream(InputStream inputStream long n)
  {
  long remaining = n; // SKIP_BUFFER_SIZE is used to determine the size of
  // skipBuffer
  int SKIP_BUFFER_SIZE = ; // skipBuffer is initialized in
  // skip(long) if needed
  byte[] skipBuffer = null;
  int nr = ;
  if (skipBuffer == null)
  {
  skipBuffer = new byte[SKIP_BUFFER_SIZE];
  }
  byte[] localSkipBuffer = skipBuffer;
  if (n <=
  {
  return ;
  }
  while (remaining >
  {
  try
  {
  nr = inputStreamread(localSkipBuffer (int) Mathmin(
  SKIP_BUFFER_SIZE remaining))
  }
  catch (IOException e)
  {
  eprintStackTrace()
  }
  if (nr <
  {
  break;
  }
  remaining = nr;
  }
  return n remaining;
  }
  /**
  * 主函數
  * @param args
  */
  public static void main(String args[])
  {
  consult()
  try
  {
  isidxclose()
  isdictclose()
  }
  catch (Exception e)
  {
  Systemoutprintln(Close files error!
  eprintStackTrace()
  }
  }
  }
  如果要在windows平台下編譯l文章中的程序代碼最好保存為cpp文件以C++項目編譯執行而且strcasecmp函數應該換為stricmp函數並且上面作者原來的程序是在linux平台下的字符編碼本身就是UTF的不需要進行編碼轉換但在windows平台下中文為gb編碼就需要進行編碼的轉換下面為需要添加修改上的字符編碼轉換後的程序
  //UTF到GB的轉換
  char* UG(const char* utf
  {
  int len = MultiByteToWideChar(CP_UTF utf NULL
  wchar_t* wstr = new wchar_t[len+];
  memset(wstr len+
  MultiByteToWideChar(CP_UTF utf wstr len)
  len = WideCharToMultiByte(CP_ACP wstr NULL NULL NULL)
  char* str = new char[len+];
  memset(str len+
  WideCharToMultiByte(CP_ACP wstr str len NULL NULL)
  if(wstr) delete[] wstr;
  return str;
  }
  //GB到UTF的轉換
  char* GU(const char* gb
  {
  int len = MultiByteToWideChar(CP_ACP gb NULL
  wchar_t* wstr = new wchar_t[len+];
  memset(wstr len+
  MultiByteToWideChar(CP_ACP gb wstr len)
  len = WideCharToMultiByte(CP_UTF wstr NULL NULL NULL)
  char* str = new char[len+];
  memset(str len+
  WideCharToMultiByte(CP_UTF wstr str len NULL NULL)
  if(wstr) delete[] wstr;
  return str;
  }
  /*
  * 顯示data內容
  */
  void display_data(char *data_buf unsigned int data_length)
  {
  fwrite(data_bufdata_lengthstdout)
  char *data=(char *)malloc(data_length)
  memcpy(datadata_bufdata_length)
  char *p=UG(data_buf)
  printf(%s\np)
  free(data)
  delete p;
  }
  以星際譯王所支持的牛津英漢詞典oxfordgb作為測試詞典格式為UTF編碼的單詞字符串然後是四個字節的int型數據表示該單詞在dict釋義文件中的起始偏移量再後四個字節的int型數據表示dict文件中該單詞釋義總共的長度如下圖所示

結果顯示能夠正確得到單詞的釋義只是音標未能正確解碼如下圖所示
 
 


From:http://tw.wingwit.com/Article/program/Java/hx/201311/25526.html
  • 上一篇文章:

  • 下一篇文章:
  • 推薦文章
    Copyright © 2005-2022 電腦知識網 Computer Knowledge   All rights reserved.