--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.hughes.android.dictionary"
+ android:versionCode="1"
+ android:versionName="1.0.0">
+ <application android:icon="@drawable/icon" android:label="@string/app_name">
+ <activity android:name=".Dictionary"
+ android:label="@string/app_name">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+ </activity>
+ </application>
+</manifest>
\ No newline at end of file
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ >
+
+<EditText android:layout_width="fill_parent" android:layout_height="wrap_content" android:id="@+id/SearchText" android:hint="Search Text"></EditText>
+
+<ListView android:layout_width="wrap_content" android:layout_height="fill_parent" android:id="@+id/SearchResults" android:choiceMode="singleChoice"></ListView>
+</LinearLayout>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="hello">Hello World, Dictionary</string>
+ <string name="app_name">Dictionary</string>
+</resources>
--- /dev/null
+package com.hughes.android.dictionary;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.util.ArrayList;
+import java.util.List;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.text.Editable;
+import android.text.TextWatcher;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+import android.widget.EditText;
+import android.widget.ListView;
+import android.widget.TextView;
+
+public class Dictionary extends Activity {
+
+ private String searchText = "";
+
+ private List<Entry> entries = new ArrayList<Entry>(100);
+
+ public static final String INDEX_FORMAT = "%s_index_%d";
+ private final File dictionaryFile = new File("/sdcard/dict-de-en.txt");
+ private final Index[] indexes = new Index[2];
+ private final byte lang = Entry.LANG1;
+
+ private DictionaryListAdapter dictionaryListAdapter = new DictionaryListAdapter();
+
+
+ /** Called when the activity is first created. */
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ Log.d("THAD", "onCreate");
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.main);
+
+ EditText searchText = (EditText) findViewById(R.id.SearchText);
+ searchText.addTextChangedListener(new DictionaryTextWatcher());
+
+ ListView searchResults = (ListView) findViewById(R.id.SearchResults);
+ searchResults.setAdapter(dictionaryListAdapter);
+
+ try {
+ loadIndex();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+
+ }
+
+ private void loadIndex() throws IOException, ClassNotFoundException {
+ Log.d("THAD", "enter loadIndex");
+ indexes[0] = new Index(String.format(INDEX_FORMAT, dictionaryFile.getAbsolutePath(), Entry.LANG1));
+ Log.d("THAD", "exit loadIndex");
+ }
+
+ void onSearchTextChange(final String searchText) {
+ this.searchText = searchText;
+ final Index.Node node = indexes[lang].lookup(searchText);
+
+ try {
+ final long length = dictionaryFile.length();
+ Log.d("THAD", "Dictionary file length=" + length);
+
+ final RandomAccessFile raf = new RandomAccessFile(dictionaryFile, "r");
+ raf.seek(length / 2);
+// final InputStreamReader dictionaryReader = new InputStreamReader(new BufferedInputStream(new FileInputStream("/sdcard/dict-de-en.txt")));
+// skip(dictionaryReader, length / 2);
+
+ for (int i = 0; i < entries.length; ++i) {
+ entries[i] = raf.readLine();
+ raf.skipBytes((int) (length / 100000));
+ }
+
+ raf.close();
+
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+
+ dictionaryListAdapter.notifyDataSetChanged();
+ }
+
+ private class DictionaryListAdapter extends BaseAdapter {
+
+ public int getCount() {
+ return 1000000;
+
+ }
+
+ public Object getItem(int position) {
+ return searchText + position + entries[position % entries.length];
+ }
+
+ public long getItemId(int position) {
+ return position;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ TextView result = null;
+ if (convertView instanceof TextView) {
+ result = (TextView) convertView;
+ } else {
+ result = new TextView(parent.getContext());
+ }
+ result.setText((String) getItem(position));
+ return result;
+ }
+
+ }
+
+ private class DictionaryTextWatcher implements TextWatcher {
+ public void afterTextChanged(Editable searchText) {
+ onSearchTextChange(searchText.toString());
+ }
+
+ public void beforeTextChanged(CharSequence arg0, int arg1, int arg2,
+ int arg3) {
+ }
+
+ public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
+ }
+ }
+
+}
\ No newline at end of file
--- /dev/null
+package com.hughes.android.dictionary;\r
+\r
+import java.util.regex.Pattern;\r
+\r
+public final class Entry {\r
+\r
+ static final byte LANG1 = 0;\r
+ static final byte LANG2 = 1;\r
+\r
+ static final Pattern lineSplitPattern = Pattern.compile("\\s+::\\s+");\r
+\r
+ String lang1 = "";\r
+ String lang2 = "";\r
+\r
+ boolean parseFromLine(final String line) {\r
+ final String[] parts = lineSplitPattern.split(line);\r
+ if (parts.length != 2) {\r
+ System.err.println("Entry:" + "Invalid line: " + line);\r
+ return false;\r
+ }\r
+ lang1 = parts[0];\r
+ lang2 = parts[1];\r
+ return true;\r
+ }\r
+\r
+ String getAllText(final byte lang) {\r
+ if (lang == LANG1) {\r
+ return lang1;\r
+ }\r
+ assert lang == LANG2;\r
+ return lang2;\r
+ }\r
+ \r
+ String getIndexableText(final byte lang) {\r
+ String text = getAllText(lang);\r
+ text = text.replaceAll("[\"\\.!?,]", "");\r
+ text = text.replaceAll("\\{[^}]+\\}", "");\r
+ return text;\r
+ }\r
+\r
+ public String normalizeToken(final String token, final byte lang) {\r
+ return token.toLowerCase().replaceAll("ß", "ss").replaceAll("ä", "ae")\r
+ .replaceAll("ö", "oe").replaceAll("ü", "ue")\r
+ .replaceAll("[^A-Za-z]", "");\r
+ }\r
+\r
+}\r
--- /dev/null
+package com.hughes.android.dictionary;\r
+\r
+import java.io.IOException;\r
+import java.io.RandomAccessFile;\r
+import java.util.Map;\r
+import java.util.TreeMap;\r
+\r
+import com.hughes.util.LRUCacheMap;\r
+\r
+\r
+public final class Index {\r
+ \r
+ final String filename;\r
+ final RandomAccessFile file;\r
+ \r
+ final Node root;\r
+ final Map<Integer,Node> locationToNode = new LRUCacheMap<Integer,Node>(5000);\r
+ \r
+ \r
+ public Index(final String filename) throws IOException {\r
+ this.filename = filename;\r
+ file = new RandomAccessFile(filename, "r");\r
+ root = getNode("", 0);\r
+ }\r
+ \r
+ public Node lookup(final String text) throws IOException {\r
+ return lookup(text, 0, root);\r
+ }\r
+ \r
+ private Node lookup(final String text, final int pos, final Node n) throws IOException {\r
+ if (pos == text.length()) {\r
+ return n;\r
+ }\r
+ for (int i = pos + 1; i <= text.length(); ++i) {\r
+ final Integer child = n.children.get(text.substring(pos, i));\r
+ if (child != null) {\r
+ return lookup(text, i, getNode(text.substring(0, i), child));\r
+ }\r
+ }\r
+ return n;\r
+ }\r
+ \r
+ private Node getNode(final String text, final int location) throws IOException {\r
+ Node node = locationToNode.get(location);\r
+ if (node == null) {\r
+ node = new Node(text, location);\r
+ locationToNode.put(location, node);\r
+ }\r
+ return node;\r
+ }\r
+\r
+ final class Node {\r
+ final String text;\r
+ final int location;\r
+ final TreeMap<String,Integer> children;\r
+ final int[] offsets;\r
+ \r
+ Node(final String text, final int location) throws IOException {\r
+ this.text = text;\r
+ this.location = location;\r
+ \r
+ file.seek(location);\r
+ final int numChildren = file.readInt();\r
+ children = new TreeMap<String, Integer>();\r
+ for (int i = 0; i < numChildren; ++i) {\r
+ final String chunk = file.readUTF().intern();\r
+ if (chunk.length() == 0) {\r
+ throw new IOException("Empty string chunk.");\r
+ }\r
+ children.put(chunk, file.readInt());\r
+ }\r
+ \r
+ final int numOffsets = file.readInt();\r
+ offsets = new int[numOffsets];\r
+ for (int i = 0; i < offsets.length; ++i) {\r
+ offsets[i] = file.readInt();\r
+ }\r
+ }\r
+ }\r
+\r
+}\r
--- /dev/null
+/* AUTO-GENERATED FILE. DO NOT MODIFY.\r
+ *\r
+ * This class was automatically generated by the\r
+ * aapt tool from the resource data it found. It\r
+ * should not be modified by hand.\r
+ */\r
+\r
+package com.hughes.android.dictionary;\r
+\r
+public final class R {\r
+ public static final class attr {\r
+ }\r
+ public static final class drawable {\r
+ public static final int icon=0x7f020000;\r
+ }\r
+ public static final class id {\r
+ public static final int SearchResults=0x7f050001;\r
+ public static final int SearchText=0x7f050000;\r
+ }\r
+ public static final class layout {\r
+ public static final int main=0x7f030000;\r
+ }\r
+ public static final class string {\r
+ public static final int app_name=0x7f040001;\r
+ public static final int hello=0x7f040000;\r
+ }\r
+}\r