2010-06-03 3 views
3

Prenez cette chaîne en entrée:Comment obtenir N chaîne aléatoire à partir d'une chaîne de format {a1 | a2 | a3}?

string s1="planets {Sun|Mercury|Venus|Earth|Mars|Jupiter|Saturn|Uranus|Neptune}{?|!|.}" 
string s2="some text {morning,night,evening} some text{?|!|.}" 

Comment pourrais-je choisir au hasard N de l'ensemble, puis les rejoindre par des virgules. L'ensemble est défini entre {} et les options sont séparées par | pipe La commande est maintenue. La chaîne peut avoir plusieurs ensembles {}.

Certains sortie pourrait être:

string output1="planets Sun, Venus."; 
string output2="planets Neptune!"; 
string output3="planets Earth, Saturn, Uranus, Neptune."; 
string output4="planets Uranus, Saturn.";// bad example, order is not correct 
string output5="some text morning!"; 

Java 1.5

+0

Ne pas utiliser regex - aller pour les tableaux et les nombres aléatoires – Amarghosh

+0

J'ai besoin d'obtenir le {} ensemble de la chaîne, qui a probablement besoin de regex, n'est-ce pas? – Pentium10

+0

D'accord - mais la partie principale est de choisir des chaînes aléatoires, non? – Amarghosh

Répondre

3

Collez les planètes dans un tableau, et supprimer des éléments aléatoires jusqu'à ce que vous avez assez. Il y a des solutions plus intéressantes, en termes algorithmiques, mais pour la quantité de données que vous traitez, c'est rapide et simple.

+1

En fait, cela peut être une excellente idée. Si la taille de l'ensemble original est M, alors considérons N et M-N: si N est plus petit que *, prenez * N éléments de M; sinon * supprimer * M-N éléments de M. –

+0

@GregS: Je suis d'accord, mais je vais réitérer que pour un si petit ensemble de données, ce n'est vraiment pas grave. –

0

Je ne suis pas sûr de la syntaxe de Java, mais il devrait être quelque chose comme ça.

string[] split = s.split("|"); 
Random r = new Random(); 
int first = r.nextInt(split.length); 
string planets = "planets " + split[first++]; 
for (; first < split.length; first++) 
{ 
    if (r.nextInt(2) == 1) 
     planets += " " + split[first]; 
} 
0

J'ai testé ce programme Java et il fonctionne:

import java.util.Random; 

/** @author Daniel Trebbien */ 
// License: Public Domain 
public class SO2965185 { 
    public static String randomFormat(final String templ) { 
     int i = templ.indexOf('{'); 
     if (i < 0) { 
      return templ; 
     } 
     else { 
      Random r = new Random(); 

      int prevI = 0; 
      StringBuilder sb = new StringBuilder(); 
      do { 
       sb.append(templ, prevI, i); 
       int j = templ.indexOf('}', i + 1); 
       if (j < 0) 
        throw new java.util.MissingFormatArgumentException(templ.substring(i)); 
       int pipeCount = 0; 
       for (int k = templ.indexOf('|', i + 1); i < k && k < j; k = templ.indexOf('|', k + 1)) 
        ++pipeCount; 
       if (pipeCount == 0) { 
        sb.append(templ, i + 1, j); 
       } 
       else { 
        String m0Selection; 
        final int m0 = r.nextInt(pipeCount + 1); // must pick one from each set 
        if (m0 >= pipeCount) { 
         m0Selection = templ.substring(templ.lastIndexOf('|', j - 1) + 1, j); 
        } 
        else { 
         int k = i + 1; 
         int m = m0; 
         for(; m > 0; --m) 
          k = templ.indexOf('|', k) + 1; 
         m0Selection = templ.substring(k, templ.indexOf('|', k + 1)); 
        } 

        int selectionCount = 0; 
        for (int n = 0; n <= pipeCount; ++n) { 
         if (n == m0) { 
          if (selectionCount != 0) 
           sb.append(", "); 
          sb.append(m0Selection); 
          ++selectionCount; 
         } 
         else if (r.nextBoolean()) { 
          int m = n; 
          if (selectionCount != 0) 
           sb.append(", "); 
          if (m >= pipeCount) { 
           sb.append(templ, templ.lastIndexOf('|', j - 1) + 1, j); 
          } 
          else { 
           int k = i + 1; 
           for(; m > 0; --m) 
            k = templ.indexOf('|', k) + 1; 
           sb.append(templ, k, templ.indexOf('|', k + 1)); 
          } 
          ++selectionCount; 
         } 
        } 
       } 
       prevI = j + 1; 
       i = templ.indexOf('{', j + 1); 
      } while(i >= 0); 
      return sb.toString(); 
     } 
    } 

    public static void main(String[] args) { 
     System.out.println(randomFormat("test")); 
     System.out.println(randomFormat("{oneOption}")); 
     System.out.println(randomFormat("{first|second}")); 
     String s1 = "planets {Sun|Mercury|Venus|Earth|Mars|Jupiter|Saturn|Uranus|Neptune}{?|!|.}"; 
     System.out.println(randomFormat(s1)); 
     //System.out.println(randomFormat("jjj{test")); 
    } 
} 

Ce programme imprime quelque chose comme:

 
test 
oneOption 
first, second 
planets Sun, Mercury, Jupiter, Neptune?, !, . 

et

 
test 
oneOption 
second 
planets Sun, Jupiter, Saturn!, . 

et

 
test 
oneOption 
first 
planets Venus, Earth, Jupiter, Saturn, Uranus, Neptune. 

Vous devez pardonner le désordre un peu parce que je le code initialement écrit pour un problème légèrement différent :)

Le code prend des combinaisons aléatoires d'entrées ayant au moins une entrée de chaque série. Donc, pour un ensemble avec N entrées, il y a 2 N - 1 combinaisons qui peuvent être générées. De plus, gardez à l'esprit la probabilité qu'il y ait exactement M entrées dans la combinaison aléatoire:

P (exactement M entrées en combinaison générée) = (N choisir M) divisé par (2 N - 1)

Exemple: N = 9 ("{Sun|Mercury|Venus|Earth|Mars|Jupiter|Saturn|Uranus|Neptune}").

P (exactement 2 entrées en combinaison générée) = 0.0704

+0

wow, c'est beaucoup plus compliqué alors j'aurais deviné la solution nécessaire. –

+1

Pensez à utiliser les regex pour localiser les motifs à remplacer. L'utilisation de 'split()' aurait également rendu votre code plus facile à lire (et évité beaucoup d'appels'ubstring() 'et'indexOf()'). D'un autre côté, j'aime l'idée de lancer une pièce pour obtenir des choix en ordre: plus propre que ma mise en œuvre. – tucuxi

0

Voici une autre option. Celui-ci choisit seulement 1 élément de {|||} ensembles, et choisit entre 1 et N éléments dans {,,,} ensembles, en les séparant par des virgules. Beau défi de programmation.

public static String generateVariant(String s) { 
    Pattern p = Pattern.compile("[{]([^}]+)[}]"); 
    Matcher m = p.matcher(s); 
    StringBuilder output = new StringBuilder(); 

    int offset = 0; 
    while (m.find()) { 
     output.append(s.substring(offset, m.start())); 
     String[] choices = m.group(1).split("[|,]"); 

     // if '|' used as separator, only echo 1 random choice 
     int n = m.group(1).contains("|") ? 1 
       : (int) (Math.random() * (choices.length - 1)) + 1; 

     // permutation with n random elements 
     int[] permutation = new int[choices.length]; 
     for (int i = 0; i < choices.length; i++) { 
      permutation[i] = i; 
     } 
     for (int i=0; i<n; i++) { 
      int r = (int)(Math.random() * (choices.length - i)) + i; 
      int aux = permutation[r]; 
      permutation[r] = permutation[i]; 
      permutation[i] = aux; 
     } 

     // sort and echo first n 
     Arrays.sort(permutation, 0, n); 
     for (int i=0; i<n; i++) { 
      output.append((i == 0 ? "" : ", ") + choices[permutation[i]]); 
     } 
     offset = m.end(); 
    } 
    output.append(s.substring(offset, s.length())); 
    return output.toString(); 
} 

public static void main(String[] args) { 
    String s1 = "planets {Sun,Mercury,Venus,Earth,Mars,Jupiter,Saturn,Uranus,Neptune}{?|!|.}"; 
    for (int i = 0; i < 10; i++) { 
     System.err.println(generateVariant(s1)); 
    } 
} 

Oui, la génération d'une permutation est surpuissant pour les {|||} ensembles.Voici une version plus courte et plus simple, où la distribution du nombre de choix n'est plus uniforme (inspiré par la réponse de Daniel Trebbien):

public static String generateVariant(String s) { 
    Pattern p = Pattern.compile("[{]([^}]+)[}]"); 
    Matcher m = p.matcher(s); 
    StringBuilder output = new StringBuilder(); 
    Random r = new Random(); 

    int offset = 0; 
    while (m.find()) { 
     output.append(s.substring(offset, m.start())); 
     String[] choices = m.group(1).split("[|,]"); 
     // if '|' used as separator, only echo 1 random choice 
     if (m.group(1).contains("|")) { 
      output.append(choices[r.nextInt(choices.length)]); 
     } else { 
      boolean first = true; 
      for (int i=0; i<choices.length; i++) { 
       if (r.nextBoolean()) { 
        output.append((first ? "" : ", ") + choices[i]); 
        first = false; 
       } 
      }     
     } 
     offset = m.end(); 
    } 
    output.append(s.substring(offset, s.length())); 
    return output.toString(); 
} 
0

Pour les planètes, il suffit d'écrire une boucle

result = empty list 
For p in planets 
    throw a dice 
    If (dice > 3) // 50% probability, adjust as required 
    append p to result 
If result is empty, start over // do this if you don't want result to be empty 

Cela donne une liste aléatoire de planètes, dans l'ordre donné.

Questions connexes