来自随机字母数字字符串的大写随机字符数

时间:2010-07-20 18:08:40

标签: java string random

我有一些内容未知的随机字符串,众所周知,内容是字母数字,小写。

我正在寻找一种简单的方法来大写该字符串中随机数字的字符。随机性越高越好。

我可以想到几种方法来做到这一点,但它们似乎都不是最优的。

好的第一个解决方案:

public String randomizeCase(String myString){
  Random rand = new Random();
  StringBuilder build = new StringBuilder();
  for(char c: myString.toCharArray()){
     String s = new String(c);
     if(Character.isLetter(c) && rand.nextBoolean()){
        s = s.toUpperCase();
     } 
     build.append(s);
  }
  return build.toString();
}

我不喜欢这个解决方案,因为:

  • 每个字符大写的几率为50%的几率不等于50%的字符大写的可能性
  • 有可能没有任何东西被装上
  • char to string conversion is ugly

3 个答案:

答案 0 :(得分:5)

解决方案取决于您选择的概率模型。例如,如果你决定binomial distribution,那么你可以遍历字符,并以固定的概率p将每个字符串切换为大写。预期的大写字母数将是p * str.length():

public static String randomUpper(String str, double p) {
    StringBuilder sb = new StringBuilder(str.length());
    for (int i = 0; i < str.length(); i++) {
        char c = str.charAt(i);
        if (Character.isLetter(c) && Math.random() < p)
            c = Character.toUpperCase(c);
        sb.append(c);
    }
    return sb.toString();
}

另一方面,如果您想确定给定字符串的超精确字母的确切数量,则问题变为random sample problem(即选择M个位置以切换字符串中的N个位置)。这可能比第一种方法快得多,当M远小于N时(尽管使用Java的不可变字符串,差异变得很小,因为你必须复制整个字符串)。

- 编辑 -

现在您已阐明要求,请考虑以下事项:

public static String randomUpper2(String str, double p) {
    int letters = 0;
    for (int i = 0; i < str.length(); i++) {
        if (Character.isLetter(str.charAt(i)))
            letters++;
    }

    int toChoose = (int) (p * letters);
    StringBuilder sb = new StringBuilder(str.length());
    for (int i = 0; i < str.length(); i++) {
        char c = str.charAt(i);
        if (Character.isLetter(c)) {
            if (Math.random() < (toChoose/(double)letters)) {
                c = Character.toUpperCase(c);
                toChoose--;
            }
            letters--;
        }           
        sb.append(c);
    }
    return sb.toString();
}

此代码根据需要“动态”执行随机样本,仅考虑alpha字符。使用p = 0.5来切换正好一半的字母。

答案 1 :(得分:3)

以下是随机样本问题的代码段(感谢Eyal为其命名)。不确定这是否是您正在寻找的。

请注意,如果字符串中没有足够的小写字母,则此解决方案将遇到infinete循环。所以你也需要解决这个问题,但我想这是一个起点。 ; - )

String myString = "9aie3ra3nr23rr5r21t";
System.out.println(upperCaseRandom(myString, 10));


public static String upperCaseRandom(String input, int n) {
 StringBuilder output = new StringBuilder(input);
 Random r = new Random();

 for (int i = 0; i < n; i++) {
  // Pick a place
  int position = r.nextInt(input.length());

  // Check if lowercase alpha
  if (Character.isLowerCase(output.charAt(position))) {
   output.setCharAt(position, Character.toUpperCase(output.charAt(position)));
  } else {
   i--;
  } 
 } 
 return output.toString();
}

修改 这是一个改进版本。它确实将n个小写字母更改为大写字母(如果有足够的话,则会更改所有字母)。程序不会遇到无限循环,但仍然运行时间是一个问题。

public static String upperCaseRandom(String input, int n) {
    final int length = input.length();
    final StringBuilder output = new StringBuilder(input);
    final boolean[] alreadyChecked = new boolean[length];
    final Random r = new Random();

    for (int i = 0, checks = 0; i < n && checks < length; i++) {
        // Pick a place
        int position = r.nextInt(length);

        // Check if lowercase alpha
        if (!alreadyChecked[position]) {
            if (Character.isLowerCase(output.charAt(position))) {
                output.setCharAt(position, Character.toUpperCase(output.charAt(position)));
            } else {
                i--;
            }
            checks++;
            alreadyChecked[position] = true;
        } else {
            i--;
        }
    }
    return output.toString();
}

答案 2 :(得分:0)

我试过

      String lowerCasedRandomString = "4210281f-76ac-96b5-ed54-5458abf788d0";
      String upperCasedRandomString = "4210281F-76AC-96B5-ED54-5458ABF788D0";
      System.out.println(lowerCasedRandomString.toUpperCase());
      System.out.println(upperCasedRandomString.toLowerCase());

我得到了输出

      4210281F-76AC-96B5-ED54-5458ABF788D0
      4210281f-76ac-96b5-ed54-5458abf788d0