2010-07-20 150 views
1

我有一些隨機字符串與未知內容,什麼是已知的內容是字母數字和小寫。從隨機字母數字字符串的大寫隨機數字

我正在尋找一個簡單的方法來大寫隨機數的字符串中的字母字符。隨機性越高越好。

我可以想到一些方法來做到這一點,但沒有一個看起來非常優秀。

好嗎第一個解決方案:

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%都大寫
  • 有可能沒有任何東西被加殼
  • 字符串轉換很醜陋
+1

也許你能簡要介紹一下你已經想出了自己的想法,然後大家一起討論那些/給予提示? – 2010-07-20 18:12:07

+0

當你說「隨機性越高越好。」你是在尋找接近真正的隨機性的字母大寫和/或哪些字母大寫? – jball 2010-07-20 18:14:39

+0

添加了一些蹩腳的代碼 – mkoryak 2010-07-20 18:28:53

回答

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

這在所有情況下都無法正常工作(嘗試它)。你可能會「切換」數字字符,導致沒有效果。如果添加isLetter()條件,問題將得到解決,但由於試驗和錯誤方法的無限性,此解決方案在大字符串(特別是多位數字)上的性能較差。 – 2010-07-20 19:24:31

+0

isLowerCase()將爲數字字符返回false,因此它不會「切換」它們。我不能重新創建你的錯誤的情況,但也許我只是不明白到目前爲止。你能重新檢查和/或重新解釋嗎? 性能問題確實是一個問題,改進後的版本不應該再次檢查相同的位置(只需添加一個布爾型[]來標識這些。而且仍然需要避免無限循環。 – 2010-07-20 20:25:30

+0

對不起,您是100%正確的代碼的正確性,我的錯誤,它比我的最後一個解決方案還要短,唯一的缺點是性能,漸近的意義,爲了轉換所有的N個字符,預期的試驗次數是N/N + N /(N-1 )+ ... + N/2 + N/1,其行爲類似於N * log N.換句話說,最壞情況的複雜度是O(N log N)而不是O(N)。這是一個普遍的問題特定的隨機樣本算法。 – 2010-07-20 21:47:11

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

此代碼「對飛」進行隨機抽樣,只考慮字母字符,按要求。使用p = 0.5切換正好一半的字母。

+0

+1。你還打我推薦'Character.toUpperCase()'。 – 2010-07-20 18:31:47

+0

當您從前到後遍歷字符串並且Match.random()比較值變小(toChoose gets變小)時,這會導致後面的字符被更改的概率降低。因此它不是一個統一的分佈。 – 2010-07-21 12:34:22

+0

@Nils:這可能看起來很明顯,但這是一種已知的算法,它會在所有可能的子集上產生均勻的分佈。查看我博客文章中的證明:http://eyalsch.wordpress.com/2010/04/01/random-sample/。請參閱「全面掃描」一節。 – 2010-07-21 12:51:11

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