How to create article spinner regex in Java?
Question: Say for example I want to take this phrase:

> {{Hello|What's Up|Howdy} {world|planet} | {Goodbye|Later} {people|citizens|inhabitants}}

and randomly make it into one of the following:

    
    
    Hello world
    Goodbye people
    What's Up word
    What's Up planet
    Later citizens
    etc.
    

The basic idea is that enclosed within every pair of braces will be an
unlimited number of choices separated by "|". The program needs to go through
and randomly choose one choice for each set of braces. Keep in mind that
braces can be nested endlessly within each other. I found a thread about this
and tried to convert it to Java, but it did not work. Here is the python code
that supposedly worked:

    
    
    import re
    from random import randint
    
    def select(m):
        choices = m.group(1).split('|')
        return choices[randint(0, len(choices)-1)]
    
    def spinner(s):
        r = re.compile('{([^{}]*)}')
        while True:
            s, n = r.subn(select, s)
            if n == 0: break
        return s.strip()
    

Here is my attempt to convert that Python code to Java.

    
    
    public String generateSpun(String text){
        String spun = new String(text);
        Pattern reg = Pattern.compile("{([^{}]*)}");
        Matcher matcher = reg.matcher(spun);
        while (matcher.find()){
           spun = matcher.replaceFirst(select(matcher.group()));
        }
        return spun;
    }
    
    private String select(String m){
        String[] choices = m.split("|");
        Random random = new Random();
        int index = random.nextInt(choices.length - 1);
        return choices[index];
    }
    

Unfortunately, when I try to test this by calling

    
    
    generateAd("{{Hello|What's Up|Howdy} {world|planet} | {Goodbye|Later} {people|citizens|inhabitants}}");
    

In the main of my program, it gives me an error in the line in generateSpun
where Pattern reg is declared, giving me a PatternSyntaxException.

    
    
    java.util.regex.PatternSyntaxException: Illegal repetition
    {([^{}]*)}
    

Can someone try to create a Java method that will do what I am trying to do?


Answer: Here are some of the problems with your current code:

  * You should _reuse_ your compiled `Pattern`, instead of `Pattern.compile` _every time_
  * You should _reuse_ your `Random`, instead of `new Random` _every time_
  * Be aware that [`String.split`](http://download.oracle.com/javase/6/docs/api/java/lang/String.html#split%28java.lang.String%29) is regex-based, so you must `split("\\|")`
  * Be aware that curly braces in Java regex must be escaped to match literally, so `Pattern.compile("\\{([^{}]*)\\}");`
  * You should query `group(1)`, not `group()` which defaults to group `0`
  * You're using `replaceFirst` wrong, look up [`Matcher.appendReplacement/Tail`](http://download.oracle.com/javase/6/docs/api/java/util/regex/Matcher.html#appendReplacement%28java.lang.StringBuffer,%20java.lang.String%29) instead
  * [`Random.nextInt(int n)`](http://download.oracle.com/javase/6/docs/api/java/util/Random.html#nextInt%28int%29) has _exclusive upper bound_ (like many such methods in Java)
  * The algorithm itself actually does not handle arbitrarily nested braces properly

Note that escaping is done by preceding with `\`, and as a Java string literal
it needs to be doubled (i.e. `"\\"` contains a single character, the
backslash).

### Attachment

  * [Source code and output with above fix but no major change to algorithm](http://ideone.com/MOoFt)

