up vote 2 down vote favorite

A string will be made up of certain symbols (ax,bx,dx,c,acc for example) and numbers.

ex: ax 5 5 dx 3 acc c ax bx

I want to replace one or all of the symbols (randomly) with another symbol of the same set. ie, replace one of {ax,bx,dx,c,acc} with one of {ax,bx,dx,c,acc}.

replacement example: acc 5 5 dx 3 acc c ax bx or c 5 5 dx 3 acc c ax ax

Is there a way to do this with regexes? In Java? If so, which methods should I use?

flag

7 Answers

up vote 0 down vote accepted

I think this is the most clean solution for replacing a certain set of symbols from a string containing a superset of them. appendreplacement is the key to this method. one important caveat: do not include any unescped dollar characters ($) in your elements list. escape them by using "\$" eventually use
.replaceall("\$","\\$"); on every string before adding it to the list. see also the javadoc in doubt about the $ signs.

import java.util.*;
import java.util.regex.Pattern;
import java.util.regex.Matcher;

public class ReplaceTokens {
public static void main(String[] args) {
    List<String> elements = Arrays.asList("ax", "bx", "dx", "c", "acc");
    final String patternStr = join(elements, "|"); //build string "ax|bx|dx|c|acc" 
    Pattern p = Pattern.compile(patternStr);
    Matcher m = p.matcher("ax 5 5 dx 3 acc c ax bx");
    StringBuffer sb = new StringBuffer();
    Random rand = new Random();
    while (m.find()){
        String randomSymbol = elements.get(rand.nextInt(elements.size()));
        m.appendReplacement(sb,randomSymbol);
    }
    m.appendTail(sb);
    System.out.println(sb);
}

/**
 * this method is only needed to generate the string ax|bx|dx|c|acc in a clean way....
 * @see org.apache.commons.lang.StringUtils.join    for a more common alternative...
 */
public static String join(List<String> s, String delimiter) {
    if (s.isEmpty()) return "";
    Iterator<String> iter = s.iterator();
    StringBuffer buffer = new StringBuffer(iter.next());
    while (iter.hasNext()) buffer.append(delimiter).append(iter.next());
    return buffer.toString();
}
link|flag
up vote 1 down vote
  1. Yes, this can be done with regexes. Probably not very prettily, not without a loop or two
  2. Yes, this can be implemented in Java.
  3. See Random, the regex package
  4. The implementation is left as an exercise for the student.
link|flag
up vote 1 down vote

To answer the first question: no.

Since you are doing a random replace, regex will not help you, nothing about regex is random. * Since your strings are in an array, you don't need to find them with any pattern matching, so again regex isn't necessary.

*Edit: the question has been edited so it no longer says the strings are in an array. In this case, assuming they are all in one big string, you might build a regex to find the parts you want to replace, as shown in other answers.

link|flag
up vote 0 down vote

@Bill

the question is not to replace strings in an array with other strings, it is to replace the symbols in the string with other random symbols.

@steveth45

aw crap.

i was thinking i can just do it the normal way: split the string into symbols and numbers, and then go over element and replace them (or not) with a string in a lookup table.

link|flag
You can respond to answers with comments, which is preferred if not offering your own answer to the question. – Julie Oct 25 '08 at 22:19
Okay, see the changes I made to my original answer. – Bill the Lizard Oct 25 '08 at 22:20
Now you can remove this non-answer. – Brad Gilbert Oct 26 '08 at 23:23
up vote 0 down vote

@Bill

with your way, you are one symbol with another symbol in the string. what i need is a way to replace those symbols with symbols that might even be in that string. for example, change "ax 5 5 dx 3 acc c ax bx" to "fff 5 5 dx 3 acc c ax bx". the "fff" isn't in the string, see.

sorry if i'm being picky, but thanks a bunch.

@Ken G care to try to make a regex for this?

link|flag
I see what you mean. – Bill the Lizard Oct 25 '08 at 22:33
See my changes, once again. :) – Bill the Lizard Oct 25 '08 at 22:51
up vote 0 down vote

Use the Random class to generate a random int to choose the index of the symbols.

    String text = "ax 5 5 dx 3 acc c ax bx";
    System.out.println("Original: " + text);
    String[] tokens = text.split(" ");
    List<Integer> symbols = new ArrayList<Integer>();
    for(int i=0; i<tokens.length; i++) {
        try {
            Integer.parseInt(tokens[i]);
        } catch (Exception e) {
            symbols.add(i);
        }
    }
    Random rand = new Random();
    // this is the part you can do multiple times
    int source = symbols.get((rand.nextInt(symbols.size())));
    int target = symbols.get((rand.nextInt(symbols.size())));
    tokens[target] = tokens[source];

    String result = tokens[0];
    for(int i=1; i<tokens.length; i++) {
        result = result + " " + tokens[i];
    }
    System.out.println("Result: " + result);

Make as many replacements as you need before you join the tokens back together.

There are two parts here that might seem tricky. First is the try catch to identify those tokens that are not integers. I recommend you pull that part out into its own method, since it works, but it's a bit hacky.

The second part is where I set the source and target variables. What I'm doing there is getting a randomly selected index of one of the non-numeric symbols. Once I have two random indexes, I can swap them in the next line.

An alternative to swapping would be to build up a new String from randomly selected symbols once you've split the original String into an array.

link|flag
up vote 0 down vote

thanks a bunch guys. here's what i came up with. see if you can come up with a more efficient way.

private final String[] symbolsPossible = {"ax","bx","cx","dx","foo"};
private boolean exists;
private final String mutate(String s)
{
String[] tokens=s.split(" ");
for(int j=0; j<tokens.length; j++)
if(Math.random()<.1) //10% chance of mutation per token
{
//checking to see if the token is a supported symbol
exists=false;
for(int i=0; i<symbolsPossible.length; i++)
    if(tokens[j].equals(symbolsPossible[i]))
       exists=true;
if(exists)
    tokens[j]=symbolsPossible[(int)Math.random()*symbolsPossible.length];
}
StringBuffer result=new StringBuffer();
for(String t:tokens)
    result.append(t);
return result;
}
link|flag

Your Answer

get an OpenID
or
never shown

Not the answer you're looking for? Browse other questions tagged or ask your own question.