iangilham.com

By on

software

I came across a fun little collection of flash cards last week – the Oblique Strategies. The only problem was that getting hold of the text of the cards in a reusable format was fairly difficult.

Fortunately, the website had a very old Windows application written in Visual Basic 3 that displays a random card on launch. This would be enough for some people, but to me, it’s an ancient and closed technology that the world is better off avoiding today. With that in mind, how can we extract the strings from the application so that they can be reused?

The application is packaged only with the VB runtime DLL and a readme file, so we know that the text of the cards must be embedded in the application’s main executable somewhere. Fortunately, I know a brilliant tool for extracting strings from Windows executables.

Enter Mark Russinovich’s Sysinternals Suite. Specifically, the strings application, which just extracts all the strings it can find from an executable and dumps the result to standard out.

So I ran the following command on the Windows command line:

strings.exe oblique.exe > oblique.txt

After cleaning up the resulting file, I had a simple text file with the text of each flashcard on a new line. I’m not inclined to challenge possible copyright violations by offering the file for download, but anyone reading this should be able to reproduce my steps easily.

All that remains is to produce a user interface. On the command line, there are a number of good ways to do this:

Unix shell:

shuf -n 1 oblique.txt

# or

rl -c 1 oblique.txt

# or

sed -n $((RANDOM%$(wc -l < leader.txt)+1))p oblique.txt

Python (v3 syntax):

One liner:

print(random.choice([line for line in open('oblique.txt')]))

Script:

import os
import random
import sys
 
def randline(fname):
    result = ''
    if os.path.exists(fname):
        result =  random.choice([line for line in open(fname)])
    return result
 
def main(*args):
    for arg in args[1:]:
        print(randline(arg))
    return 0
 
if __name__ == "__main__":
        sys.exit(main(*sys.argv))