случайное количество символов в верхнем регистре из случайной буквенно-цифровой строки - PullRequest
1 голос
/ 20 июля 2010

У меня есть некоторая случайная строка с неизвестным содержимым, известно, что содержимое является буквенно-цифровым и в нижнем регистре.

Я ищу простой способ прописать случайное количество букв алфавита в этой строке. Чем выше случайность, тем лучше.

Я могу придумать несколько способов сделать это, но ни один из них не кажется оптимальным.

хорошо, первое решение:

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% вероятности того, что 50% символов в верхнем регистре
  • Существует вероятность того, что ничего не повышается в корпусе
  • преобразование символа в строку ужасно

Ответы [ 3 ]

5 голосов
/ 20 июля 2010

Решение зависит от выбранной вами вероятностной модели. Например, если вы выбрали биномиальное распределение , то вы можете пересечь символы и переключить каждый символ в верхний регистр с фиксированной вероятностью 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();
}

Если, с другой стороны, вы хотите определиться с точным количеством букв в верхнем регистре для данной строки, то проблема становится проблемой случайной выборки (т.е. выберите 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();
}

Этот код выполняет случайную выборку «на лету», при необходимости учитывая только альфа-символы. Используйте p = 0.5 для переключения ровно половины букв.

3 голосов
/ 20 июля 2010

Вот фрагмент кода для случайной задачи (спасибо Eyal за то, что назвали его). Не уверен, что это то, что вы ищете.

Имейте в виду, что это решение попадет в бесконечный цикл, если в строке недостаточно строчных букв. Так что вам также нужно будет заняться этим, но я думаю, что это отправная точка. ; -)

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

Edit: Вот улучшенная версия. Он действительно меняет ровно 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();
}
0 голосов
/ 09 апреля 2015

Я пытался с

      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
...