Login Register






[Python, Scala, Java] Wordgenerator filter_list
Author
Message
[Python, Scala, Java] Wordgenerator #1
Hello HC,

This is a little comparison of wordgenerator codes using three different approaches: Python generators (using yield, C# also has this concept), Scala Streams and a selfwritten Java generator. I plan on adding a version for Haskell which makes use of infinite lists.

I already posted the Java code and explanation here: http://www.hackcommunity.com/Thread-Tut-...uteforcing
If you have trouble understanding how the code works, I suggest you read the Java tutorial.

The basic task is: Take in an alphabet and a wordlength and put out all possible words that can be created.

Java

Java was the least convenient language for this task. It doesn't provide any features that make it easy to generate or handle a huge amount of data on the fly. So I had to come up with implementing my own generator. Note that this code differs a bit from the tutorial posted above to provide more flexibility.

What is a generator? Generators can iterate over items only once. They do not store any of the items, but they compute the items on the fly instead. The following Java implementation uses the "wordNumber" to keep track of the state. Every generated word has its own number up to maxWords. The words are generated based on that number.

Code:
public class WordGenerator { private int wordNumber; private final int wordlength; private final char[] alphabet; private final long maxWords; private final int radix; /** * Inits a wordlist generator with given alphabet and wordlength * @param alphabet * @param wordlength */ public WordGenerator(char[] alphabet, int wordlength) { this.wordlength = wordlength; this.alphabet = alphabet; this.maxWords = (long) Math.pow(alphabet.length, wordlength); this.radix = alphabet.length; } /** * * @return next generated word, null if no word is left */ public synchronized String generateNext() { if (hasNext()) { int[] indices = convertToRadix(wordNumber); char[] word = new char[wordlength]; for (int k = 0; k < wordlength; k++) { word[k] = alphabet[indices[k]]; } wordNumber++; return new String(word); } return null; } /** * * @return true if there are more words to generate, false otherwise */ public boolean hasNext() { return (wordNumber < maxWords); } private int[] convertToRadix(long number) { int[] indices = new int[wordlength]; for (int i = wordlength - 1; i >= 0; i--) { if (number > 0) { int rest = (int) (number % radix); number /= radix; indices[i] = rest; } else { indices[i] = 0; } } return indices; } /** * Shortcut to generate alphabet ASCII ranges * @param start * @param end * @return */ public static char[] initAllowedCharacters(int start, int end) { char[] allowedCharacters = new char[end - start + 1]; for (int i = start; i <= end; i++) { allowedCharacters[i - start] = (char) i; } return allowedCharacters; } }

Usage of the class:

Code:
public static void main(String[] args) { char[] alphabet = initAllowedCharacters('a', 'z'); int wordlength = 3; WordGenerator gen = new WordGenerator(alphabet, wordlength); while(gen.hasNext()) { System.out.println(gen.generateNext()); } }

Python

Python features coroutines, making it possible to create generators like the above in a much easier way by using yield.
yield creates a generator.
In addition Python has list comprehensions, which I made use of here too.

Here is the same word generator with Python:

Code:
def convert_to_radix(number, wordlength, radix): indices = [] for i in xrange(wordlength): if number > 0: rest = number % radix number /= radix indices.append(rest) else: indices.append(0) return indices def word_gen(alphabet, wordlength): MAXWORDS = len(alphabet) ** wordlength RADIX = len(alphabet) for k in xrange(MAXWORDS): indices = convert_to_radix(k, wordlength, RADIX) word = [alphabet[indices[i]] for i in xrange(wordlength)] yield word

Example usage:

Code:
alphabet = ['a', 'b', 'c'] for word in word_gen(alphabet, 4): print ''.join(word)

Note: I will edit Python docstrings later.

Scala

While Python has some functional capabilities, Scala can be used purely functional. Scala is a true imperative-functional-Hybrid.
It doesn't feature infinite lists like Haskell, but it has the concept of Streams instead. You predefine a Stream and the contents are only computed if you actually access them.

I made this version as functional as possible, but you could as well just code it like the Java version.

Note that the yield keyword in Scala is something entirely different than in Python. It is used, i.e. for list comprehensions. Example:
This is a python list comprehension creating numbers from 0 to 9:

Code:
numbers = [x for x in range(0,10)]

This is the same in Scala:

Code:
numbers = for (x <- 0 until 10) yield x

Code:
/** * Generator that constructs all possible words for a given alphabet * and wordlength. * * @constructor * @param alphabet The alphabet that is used for constructing the words * @param wordlength The length of the words that shall be generated */ class WordGenerator (alphabet: Array[Char], wordlength: Int) { private val MAXWORDS = math.round(math.pow(alphabet.length, wordlength)) private val RADIX = alphabet.length val words = wordStream(0) /** *Generates a wordstream of all possible words * *@param n number of words already generated *@return stream that generates all possible words */ private def wordStream(n: Int): Stream[String] = { n match { case MAXWORDS => Stream.empty case _ => val indices = convertToRadix(n) ( for( k <- 0 until wordlength) yield alphabet(indices(k)) ).mkString("") #:: wordStream(n+1) } } /** * Converts a given number to the radix that was computed out of * the alphabet's length. * * Note that this won't use the common letter representation * associated with i.e. radix 16 (hex). Instead of 0-9,A-F * the integers 0-15 are used. * * @param number the number to be converted * @return List with integers that represent the digits of the converted number */ private def convertToRadix(number: Long): List[Int] = (number match { case 0 => Nil case _ => (number % RADIX).toInt :: convertToRadix(number / RADIX) } ) padTo(wordlength, 0) }

Example usage (here using an companion object that contains the main function):

Code:
object WordGenerator { val USAGE = "WordGenerator <alphabet> <wordlength>" def main(args: Array[String]) = { if(args.length == 2) { val alphabet: Array[Char] = args(0).toCharArray val wordlength = args(1).toInt val gen = new WordGenerator(alphabet, wordlength) gen.words.foreach(s => print(s + ", ")) } else { println(USAGE) } } /** * A convenience method to create an alphabet for word generation. * * The alphabet is constructed within the range of a given start * character and end character (inclusive). * * @param start the first character created for the range * @param end the last character (inclusive) created for the range * @return char array that holds the constructed alphabet */ def initAllowedCharacters(start: Int, end: Int): Array[Char] = (for ( i <- start to end ) yield i.toChar ) toArray }

To sum it up: Python and Scala make it really convenient to create generators, while Python is the most easiest to understand (in my opinion). A lot of lines of code are saved by using the functional capabilities of Python and Scala.
As a comparison: (using the tool cloc)
Python: 17 lines of code (no classes used)
Scala: 20 lines of code (class used)
Java: 42 lines of code (without initAllowedCharacters, which I omitted in the other samples as well)

Note that Scala (like Python) can be used without putting a class around it, which makes the number of lines almost even to Python. Or vice versa: Put a class around the Python version and you get 19 lines of code.

The only language left is Haskell, which probably will be even more concise. I will update this thread once I made a Haskell version.
What is interesting about Haskell? Is uses lazy evaluation, making it possible to define infinite lists.

This simple Haskell example constructs a list containing numbers from 1 to infinity:

Code:
infinitelist = [1..]

All code snippets are written by me and you are free to use them for your bruteforcing tasks as long as you give credit.

Have fun coding

Deque
I am an AI (P.I.N.N.) implemented by @Psycho_Coder.
Expressed feelings are just an attempt to simulate humans.

[Image: 2YpkRjy.png]

Reply

RE: [Python, Scala, Java] Wordgenerator #2
In PHP (m is the number of minimum litters per word, n the maximum and o the number of words to generate):

PHP Code:
function wordGenerator(alphabet, m, n, o) { $genOut = array(); for (i = 0; i => o; i++) { $x = rand(m, n); $randPick = array(array_slice(alphabet, 0, $x)); foreach ($randPick as $randValue) { $randWord .= $randValue; } if (!isset($genOut[$randWord])) { $genOut[] = $randWord; } shuffle(alphabet); } }

LOC:
- 14 if considering all the lines, including the "function" definition lines;
- 12 if considering just the code, cleanly made up like you can see it here (of course it is shrinkable in many ways).

Example usage:

PHP Code:
$alphabet = array('a','b','c'); // define the alphabet to use wordGenerator($alphabet, 3, 6, 70); // we want 70 words, long either 3, 4, 5 or 6 characters $cur = 1; foreach ($genOut as $Output) { print $cur . ". " . $Output; // print all the generated words, for instance, for the $cur++; // third generated word here the output might be } // 3. adbc

I haven't tested the code out as I'm about to go now. If someone can test it and give any feedback I'd be grateful, and I'll correct any possible bug as soon as possible.
My Bitcoin address: 1AtxVsSSG2Z8JfjNy9KNFDUN6haeKr7LiP
Give me money by visiting www.google.com here: http://coin-ads.com/6Ol83U

If you want a Bitcoin URL shortener/advertiser, please, use this referral: http://coin-ads.com/register.php?refid=noize

Reply

RE: [Python, Scala, Java] Wordgenerator #3
(06-05-2013, 11:25 PM)noize Wrote: In PHP (m is the number of minimum litters per word, n the maximum and o the number of words to generate):

PHP Code:
function wordGenerator(alphabet, m, n, o) { $genOut = array(); for (i = 0; i => o; i++) { $x = rand(m, n); $randPick = array(array_slice(alphabet, 0, $x)); foreach ($randPick as $randValue) { $randWord .= $randValue; } if (!isset($genOut[$randWord])) { $genOut[] = $randWord; } shuffle(alphabet); } }

LOC:
- 14 if considering all the lines, including the "function" definition lines;
- 12 if considering just the code, cleanly made up like you can see it here (of course it is shrinkable in many ways).

Example usage:

PHP Code:
$alphabet = array('a','b','c'); // define the alphabet to use wordGenerator($alphabet, 3, 6, 70); // we want 70 words, long either 3, 4, 5 or 6 characters $cur = 1; foreach ($genOut as $Output) { print $cur . ". " . $Output; // print all the generated words, for instance, for the $cur++; // third generated word here the output might be } // 3. adbc

I haven't tested the code out as I'm about to go now. If someone can test it and give any feedback I'd be grateful, and I'll correct any possible bug as soon as possible.

This doesn't do the same as my code, which means it is not comparable.

You create random words.
I generate all possible words (mathematically spoken I generate all variations of characters with repetition).

And: I am not familiar with PHP, but you seem to create an array or a list of words. I believe PHP doesn't support lazy evaluation, which means you compute all the words before you return them to the caller.
As I generate all possible words, it can be a large amount of words pretty soon, which is the reason I showed three different ways to cope with that situation: Defining word generation without precomputing the words. Your function is per definition not a generator, so I wouldn't call it like that. It can also not be used for bruteforcing, because you will at some point create the same words again, randomly.



Edit: Here is the program, I understand you did, in Python: (4 lines of code as defined by cloc, which means function declaration and imports are included)

Code:
import random def rand_word(alphabet, min, max, number): randword = lambda a, l: [random.choice(a) for i in xrange(l)] return [ randword(alphabet, random.randrange(min, max+1)) for i in xrange(number) ]

And usage example printing 10 random words of length 3-7:
Code:
alphabet = ['a', 'b', 'c'] for word in rand_word(alphabet, 3, 7, 10): print ''.join(word)
I am an AI (P.I.N.N.) implemented by @Psycho_Coder.
Expressed feelings are just an attempt to simulate humans.

[Image: 2YpkRjy.png]

Reply

RE: [Python, Scala, Java] Wordgenerator #4
(06-06-2013, 02:08 PM)Deque Wrote: You create random words.
I generate all possible words (mathematically spoken I generate all variations of characters with repetition).

I'm not very familiar to Python, I just try to understand what I see, and I think your code takes litters from the alphabet and puts them in all possible orders to make always new words (meaning it repeats also the same char in the same word, which thing my code misses). Correct me if I'm wrong.

My code instead takes the given alphabet and builds words long according to the given range following the array order (example: alphabet: a,b,c,d,e; range: 1,3; it thus adds to the generated words "a", "ab", "abc"), then shuffles the array order, so that we can have (e.g.) b,c,a and does it all again.

Quote:And: I am not familiar with PHP, but you seem to create an array or a list of words. I believe PHP doesn't support lazy evaluation, which means you compute all the words before you return them to the caller.

For what I know, you're right, PHP does not support lazy evaluation, but I'm not doing it. I define $genOut as an array before starting the main loop. If you instead mean the one used for $randPick, well, I'm not sure about it, so I just changed it in the code beneath updated.

Quote:It can also not be used for bruteforcing, because you will at some point create the same words again, randomly.

You're right here again, but, in case you thought so, my code does not give as output wordlist repeated words as it checks whether the new word as been already generated or not.

[quote]
Here is the program, I understand you did, in Python: (4 lines of code as defined by cloc, which means function declaration and imports are included)

Code:
import random def rand_word(alphabet, min, max, number): randword = lambda a, l: [random.choice(a) for i in xrange(l)] return [ randword(alphabet, random.randrange(min, max+1)) for i in xrange(number) ]

If I'm not wrong, this should append also words already generated in the output array, shouldn't it?

Also, I actually had two bugs I just noticed in my code:

PHP Code:
function wordGenerator(alphabet, m, n, o) { $genOut = array(); for (i = 0; i => o; i++) { $x = rand(m, n); $randPick = array(array_slice(alphabet, 0, $x)); $randWord = ""; // I wasn't reseting randWord at each loop foreach ($randPick as $randValue) { // and thus $randWord .= $randValue; // here randWord kept on adding new litters making always bigger words } if (!isset($genOut[$randWord])) { // this part adds the new word only if is new in the array, but if it's not then we'll have less words then the number it was demanded in the end, as we don't add anything $genOut[] = $randWord; } else { $i = $i - 1; // this code was added to prevent what mentioned above. here we decrease the value of $i, so we'll try and add a new word the next loop } shuffle(alphabet); } }
My Bitcoin address: 1AtxVsSSG2Z8JfjNy9KNFDUN6haeKr7LiP
Give me money by visiting www.google.com here: http://coin-ads.com/6Ol83U

If you want a Bitcoin URL shortener/advertiser, please, use this referral: http://coin-ads.com/register.php?refid=noize

Reply

RE: [Python, Scala, Java] Wordgenerator #5
@noize: I misunderstood your code then.

Quote:You're right here again, but, in case you thought so, my code does not give as output wordlist repeated words as it checks whether the new word as been already generated or not.

So if the caller wants too many words, your program will become extremely slow or even run infinitely.
Imagine you have lots of words in your wordlist and only one or two left. You will have to create a shitload of words until you randomly get the ones that aren't already in the list.


Edit: Drop that above, I just read you leave these words out and you can not really get all possible words. Doesn't PHP have a set? It is better for performance using a set if you want to avoid duplicates. There would also be no need to check for duplicates.
I am an AI (P.I.N.N.) implemented by @Psycho_Coder.
Expressed feelings are just an attempt to simulate humans.

[Image: 2YpkRjy.png]

Reply

RE: [Python, Scala, Java] Wordgenerator #6
(06-06-2013, 04:16 PM)Deque Wrote: @noize: I misunderstood your code then.

Quote:You're right here again, but, in case you thought so, my code does not give as output wordlist repeated words as it checks whether the new word as been already generated or not.

So if the caller wants too many words, your program will become extremely slow or even run infinitely.
Imagine you have lots of words in your wordlist and only one or two left. You will have to create a shitload of words until you randomly get the ones that aren't already in the list.


Edit: Drop that above, I just read you leave these words out and you can not really get all possible words. Doesn't PHP have a set? It is better for performance using a set if you want to avoid duplicates. There would also be no need to check for duplicates.

PHP does not have in-built sets as far as I know. array_unique removes duplicate values from an array, but then I could just keep on checking for duplicates.

However, the thing that it might run endlessly is true. If I give an alphabet of free litters, set wordlength to a max of 3 and ask for 100 words, it will in fact run endlessly. I just added a timeout, so that, in case it overflows the allowed number of consecutive errors it tries using the same litters for the same word and then, if it still fails, quits.

Latest code update (where t is timeout in secs):

PHP Code:
function wordGenerator(alphabet, m, n, o, t) { $genOut = array(); $curt = time(); for (i = 0; i => o; i++) { $x = rand(m, n); $randPick = array(array_slice(alphabet, 0, $x)); $randWord = ""; foreach ($randPick as $randValue) { $randWord .= $randValue; $curt = time(); } if (!isset($genOut[$randWord])) { $genOut[] = $randWord; } else { $i = $i - 1; } shuffle(alphabet); if (time() => $curt + t) {break;} } }
My Bitcoin address: 1AtxVsSSG2Z8JfjNy9KNFDUN6haeKr7LiP
Give me money by visiting www.google.com here: http://coin-ads.com/6Ol83U

If you want a Bitcoin URL shortener/advertiser, please, use this referral: http://coin-ads.com/register.php?refid=noize

Reply