web-dev-qa-db-fra.com

Comment diviser une chaîne entre lettres et chiffres (ou entre chiffres et lettres)?

J'essaie de trouver un moyen de fractionner une chaîne en Java qui suit un modèle comme ceci:

String a = "123abc345def";

Les résultats devraient être les suivants:

x[0] = "123";
x[1] = "abc";
x[2] = "345";
x[3] = "def";

Cependant, je suis complètement perplexe quant à la manière d'y parvenir. S'il vous plaît, quelqu'un peut-il m'aider? J'ai essayé de rechercher en ligne un problème similaire, mais il est très difficile de le formuler correctement dans une recherche.

Veuillez noter: Le nombre de lettres et de chiffres peut varier (par exemple, il pourrait y avoir une chaîne comme '1234a5bcdef')

49
The Crazy Chimp

Vous pouvez essayer de vous séparer sur (?<=\D)(?=\d)|(?<=\d)(?=\D), comme:

str.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");

Il fait correspondre les positions entre un nombre et non un nombre (dans n'importe quel ordre).

  • (?<=\D)(?=\d) - correspond à une position entre un non-chiffre (\D) et un chiffre (\d)
  • (?<=\d)(?=\D) - correspond à une position entre un chiffre et un non-chiffre.
86
Qtax

Que diriez-vous:

private List<String> Parse(String str) {
    List<String> output = new ArrayList<String>();
    Matcher match = Pattern.compile("[0-9]+|[a-z]+|[A-Z]+").matcher(str);
    while (match.find()) {
        output.add(match.group());
    }
    return output;
}
9
nullpotent

Vous pouvez essayer ceci:

Pattern p = Pattern.compile("[a-z]+|\\d+");
Matcher m = p.matcher("123abc345def");
ArrayList<String> allMatches = new ArrayList<>();
while (m.find()) {
    allMatches.add(m.group());
}

Le résultat (allMatches) sera:

["123", "abc", "345", "def"]
7
Thế Anh Nguyễn

Utilisez deux modèles différents: [0-9]* et [a-zA-Z]* et divisé deux fois par chacun d'eux.

3
mishadoff

Si vous recherchez une solution sans utiliser la fonctionnalité Java String (c'est-à-dire split, match, etc.), les éléments suivants devraient vous aider:

List<String> splitString(String string) {
        List<String> list = new ArrayList<String>();
        String token = "";
        char curr;
        for (int e = 0; e < string.length() + 1; e++) {
            if (e == 0)
                curr = string.charAt(0);
            else {
                curr = string.charAt(--e);
            }

            if (isNumber(curr)) {
                while (e < string.length() && isNumber(string.charAt(e))) {
                    token += string.charAt(e++);
                }
                list.add(token);
                token = "";
            } else {
                while (e < string.length() && !isNumber(string.charAt(e))) {
                    token += string.charAt(e++);
                }
                list.add(token);
                token = "";
            }

        }

        return list;
    }

boolean isNumber(char c) {
        return c >= '0' && c <= '9';
    }

Cette solution divisera les nombres et les "mots", où les "mots" sont des chaînes qui ne contiennent pas de nombres. Cependant, si vous ne souhaitez avoir que des "mots" contenant des lettres anglaises, vous pouvez facilement le modifier en ajoutant plus de conditions (comme l'appel de méthode isNumber) en fonction de vos besoins (par exemple, vous pouvez ignorer les mots qui contiennent lettres non anglaises). Notez également que la méthode splitString renvoie ArrayList qui peut ensuite être convertie en tableau String.

2
sergeyan

N'a pas utilisé Java pour les âges, donc juste un pseudo code, qui devrait vous aider à démarrer (plus rapide pour moi que de tout rechercher :)).

 string a = "123abc345def";
 string[] result;
 while(a.Length > 0)
 {
      string part;
      if((part = a.Match(/\d+/)).Length) // match digits
           ;
      else if((part = a.Match(/\a+/)).Length) // match letters
           ;
      else
           break; // something invalid - neither digit nor letter
      result.append(part);
      a = a.SubStr(part.Length - 1); // remove the part we've found
 }
1
Mario

Je faisais ce genre de chose pour le code critique de mission. Comme chaque fraction de seconde compte, car je dois traiter 180 000 entrées en un temps inaperçu. J'ai donc ignoré l'expression régulière et divisé complètement et autorisé le traitement en ligne de chaque élément (bien que les ajoutant à un ArrayList<String> serait bien). Si vous voulez faire exactement cela mais que vous voulez que ce soit quelque chose comme 20 fois plus vite ...

void parseGroups(String text) {
    int last = 0;
    int state = 0;
    for (int i = 0, s = text.length(); i < s; i++) {
        switch (text.charAt(i)) {
            case '0':
            case '1':
            case '2':
            case '3':
            case '4':
            case '5':
            case '6':
            case '7':
            case '8':
            case '9':
                if (state == 2) {
                    processElement(text.substring(last, i));
                    last = i;
                }
                state = 1;
                break;
            default:
                if (state == 1) {
                    processElement(text.substring(last, i));
                    last = i;
                }
                state = 2;
                break;
        }
    }
    processElement(text.substring(last));
}
1
Tatarize

Ce "d+|D+" Ne ferait-il pas le travail à la place de la lourde: "(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)"?

0
Andrew Anderson