// uses Lucene to search a text file and return the matching lines // download from a mirror suggested at http://www.apache.org/dyn/closer.cgi/lucene/java/ // and put the lucene core jar file in your sketch 'code' folder (drag and drop it into Processing) // I used lucene-core-2.2.0.jar from the lucene-2.2.0.zip download // SimpleLucene is a class I wrote to wrap around some simple lucene calls SimpleLucene engine; // this is what we're searching for // Lucene has all kinds of magic, add a ~ for fuzziness, a * or ? for wildcards, etc String searchTerm = "machine"; int[] indexes; PFont font; Vector data = new Vector(); // the line we started indexing from int startIndex = 0; void setup() { size(400, 400); font = createFont("Helvetica", 10); data = new Vector(); // http://www.gutenberg.org/files/35/35.txt - H.G. Wells' The Time Machine from Project Gutenberg String[] lines = loadStrings("35.txt"); // let's look for the start of the proper book... for (int i = 0; i < lines.length; i++) { if (lines[i].startsWith("*** START OF THIS PROJECT GUTENBERG EBOOK THE TIME MACHINE ***")) { startIndex = i+1; break; } } // now let's add the actual story text to our Vector for (int i = startIndex; i < lines.length; i++) { data.add(lines[i]); if (lines[i].startsWith("*** END OF THIS PROJECT GUTENBERG EBOOK THE TIME MACHINE ***")) { break; } } // build the index from the Vector... it doesn't have to be a Vector here, // any List containing classes with a working toString() function will work println("building/loading index:"); int ms = millis(); engine = new SimpleLucene(this, data); println(" done in " +((float)(millis()-ms)/1000.0) + " seconds"); indexes = engine.search(searchTerm); } void draw() { background(255); fill(255,0,0); textFont(font,10); // this adds a blinking cursor after your text, at the expense of redrawing everything every frame text("query: " + searchTerm+(frameCount/10 % 2 == 0 ? "_" : ""), 5, 20); if (indexes != null) { for (int i = 0; i < indexes.length; i++) { String label = data.get(indexes[i]).toString(); if (label.toLowerCase().equals(searchTerm.toLowerCase())) { fill(0,255,0); } else if (i == searchChoice-1) { fill(255,128,0); } else { fill(0); } text("line " + (startIndex+indexes[i]) + ": " + label, 5, 40 + 20*i); } } else { text("no matches found", 5, 40); } } int searchChoice = 0; void keyReleased() { if (key != CODED) { switch(key) { case BACKSPACE: searchTerm = searchTerm.substring(0,max(0,searchTerm.length()-1)); searchChoice = 0; break; case TAB: searchChoice = searchChoice + 1; if (searchChoice > indexes.length) { searchChoice = 0; } return; case ENTER: case RETURN: if (searchChoice > 0) { searchTerm = data.get(indexes[searchChoice-1]).toString(); } searchChoice = 0; break; case ESC: return; case DELETE: return; default: searchTerm += key; } } indexes = engine.search(searchTerm); }