2

字符串将由某些符号(例如 ax、bx、dx、c、acc)和数字组成。

例如:ax 5 5 dx 3 acc c ax bx

我想用同一集合的另一个符号(随机)替换一个或所有符号。即,将 {ax,bx,dx,c,acc} 之一替换为 {ax,bx,dx,c,acc} 之一。

替换示例:acc 5 5 dx 3 acc c ax bx 或 c 5 5 dx 3 acc c ax ax

有没有办法用正则表达式做到这一点?在 Java 中?如果是这样,我应该使用哪些方法?

4

5 回答 5

2

我认为这是从包含它们的超集的字符串中替换特定符号集的最干净的解决方案。appendreplacement 是这个方法的关键。一个重要的警告:不要在元素列表中包含任何未转义的美元字符 ($)。使用 "\$" 转义它们,最终使用
.replaceall("\$","\\$"); 在将每个字符串添加到列表之前。另请参阅对 $ 符号有疑问的javadoc 。

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();
}
于 2008-10-25T23:19:43.947 回答
1

回答第一个问题:没有。

由于您正在执行随机替换,因此正则表达式不会帮助您,正则表达式的任何内容都不是随机的。* 由于您的字符串在一个数组中,因此您不需要使用任何模式匹配来查找它们,因此再次不需要正则表达式。

**编辑:问题已被编辑,因此不再说字符串在数组中。在这种情况下,假设它们都在一个大字符串中,您可以构建一个正则表达式来查找要替换的部分,如其他答案所示。*

于 2008-10-25T22:02:52.480 回答
0

使用Random类生成一个随机 int 来选择符号的索引。

    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);

在将令牌重新组合在一起之前,根据需要进行尽可能多的替换。

这里有两个部分可能看起来很棘手。首先,try catch 来识别那些不是整数的标记。我建议您将该部分提取到它自己的方法中,因为它可以工作,但它有点 hacky。

第二个是我设置sourcetarget变量的地方。我在那里做的是随机选择一个非数字符号的索引。一旦我有两个随机索引,我可以在下一行交换它们。

另一种方法是,在将原始字符串拆分为数组后,从随机选择的符号中构建一个新字符串。

于 2008-10-25T22:10:02.123 回答
0
  1. 是的,这可以通过正则表达式来完成。可能不是很漂亮,不是没有一两个循环
  2. 是的,这可以在 Java 中实现。
  3. 请参阅Random正则表达式
  4. 该实现留给学生作为练习。
于 2008-10-25T22:15:17.183 回答
-1

谢谢一群人。这就是我想出的。看看你能不能想出一个更有效的方法。

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;
}
于 2008-10-26T01:42:08.777 回答