web-dev-qa-db-fra.com

Java - Chaîne de fractionnement par nombre et lettres

J'ai donc, par exemple, une chaîne telle que celle-ci C3H20IO

Ce que je veux faire, c'est scinder cette chaîne pour que je reçoive ce qui suit:

Array1 = {C,H,I,O}
Array2 = {3,20,1,1}

Le 1 en tant que troisième élément du Array2 indique la nature monoatomique de l'élément I. Idem pour O. C'est en fait la partie avec laquelle je me bats.

C'est une équation chimique, il faut donc séparer les éléments en fonction de leur nom, de la quantité d'atomes, etc.

11
Azazel

Vous pouvez essayer cette approche: 

String formula = "C3H20IO";

//insert "1" in atom-atom boundry 
formula = formula.replaceAll("(?<=[A-Z])(?=[A-Z])|(?<=[a-z])(?=[A-Z])|(?<=\\D)$", "1");

//split at letter-digit or digit-letter boundry
String regex = "(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)";
String[] atoms = formula.split(regex);

Sortie: 

atomes: [C, 3, H, 20, I, 1, O, 1] 

Maintenant, tous les indices pairs (0, 2, 4 ...) sont des atomes et les impairs sont le nombre associé: 

String[] a = new String[ atoms.length/2 ];
int[] n = new int[ atoms.length/2 ];

for(int i = 0 ; i < a.length ; i++) {
    a[i] = atoms[i*2];
    n[i] = Integer.parseInt(atoms[i*2+1]);
}

Sortie: 

a: [C, H, I, O]
n: [3, 20, 1, 1]

8
Maljam

Vous pouvez utiliser une expression régulière pour glisser sur votre entrée à l'aide de la méthode Matcher.find () .

Voici un exemple approximatif de ce à quoi cela pourrait ressembler:

    String input = "C3H20IO";

    List<String> array1 = new ArrayList<String>();
    List<Integer> array2 = new ArrayList<Integer>();

    Pattern pattern = Pattern.compile("([A-Z][a-z]*)([0-9]*)");
    Matcher matcher = pattern.matcher(input);               
    while(matcher.find()){
        array1.add(matcher.group(1));

        String atomAmount = matcher.group(2);
        int atomAmountInt = 1;
        if((atomAmount != null) && (!atomAmount.isEmpty())){
            atomAmountInt = Integer.valueOf(atomAmount);
        }
        array2.add(atomAmountInt);
    }

Je sais qu'il manque la conversion de List en Array, mais cela devrait vous donner une idée de la façon d'aborder votre problème.

4
Alexander

Une approche sans REGEX et des données stockées à l'aide de ArrayList:

String s = "C3H20IO";

char Chem = '-';
String val = "";
boolean isFisrt = true;
List<Character> chemList = new ArrayList<Character>();
List<Integer> weightList = new ArrayList<Integer>();
for (char c : s.toCharArray()) {
    if (Character.isLetter(c)) {
        if (!isFisrt) {
            chemList.add(Chem);
            weightList.add(Integer.valueOf(val.equals("") ? "1" : val));
            val = "";
        }
        Chem = c;
    } else if (Character.isDigit(c)) {
        val += c;
    } 
    isFisrt = false;
}
chemList.add(Chem);
weightList.add(Integer.valueOf(val.equals("") ? "1" : val));

System.out.println(chemList);
System.out.println(weightList);

SORTIE:

[C, H, I, O]
[3, 20, 1, 1]
4
mmuzahid

Cela fonctionne en supposant que chaque élément commence par une lettre majuscule, c'est-à-dire que si vous avez "Fe", vous ne le représentez pas dans String par "FE". Fondamentalement, vous divisez la chaîne de chaque lettre majuscule, puis chaque nouvelle chaîne en lettres et en chiffres, en ajoutant "1" si la nouvelle division ne contient aucun nombre.

        String s = "C3H20IO";
        List<String> letters = new ArrayList<>();
        List<String> numbers = new ArrayList<>();

        String[] arr = s.split("(?=\\p{Upper})");  // [C3, H20, I, O]
        for (String str : arr) {  //[C, 3]:[H, 20]:[I]:[O]
            String[] temp = str.split("(?=\\d)", 2);
            letters.add(temp[0]);
            if (temp.length == 1) {
                numbers.add("1");
            } else {
                numbers.add(temp[1]);
            }
        }
        System.out.println(Arrays.asList(letters)); //[[C, H, I, O]]
        System.out.println(Arrays.asList(numbers)); //[[3, 20, 1, 1]]
2
anaxin

Je suggère de scinder la lettre majuscule en utilisant une expression rationnelle à largeur nulle (pour extraire des éléments tels que C12, O2, Si), puis diviser chaque élément en élément et son poids numérique: 

List<String> elements = new ArrayList<>();
List<Integer> weights = new ArrayList<>();

String[] items = "C6H12Si6OH".split("(?=[A-Z])");  // [C6, H12, Si6, O, H]
for (String item : items) {
    String[] pair = item.split("(?=[0-9])", 2);    // e.g. H12 => [H, 12], O => [O]
    elements.add(pair[0]);
    weights.add(pair.length > 1 ? Integer.parseInt(pair[1]) : 1);
}
System.out.println(elements);  // [C, H, Si, O, H]
System.out.println(weights);   // [6, 12, 6, 1, 1]
1
Alex Salauyou

make (pour la boucle) avec la taille de la longueur en entrée et ajouter la condition suivante

if(i==number)
// add it to the number array

if(i==character)
//add it into character array
1
Thesoham24

Est-ce que c'est bon? (Ne pas utiliser split)

Regex Demo

String line = "C3H20ZnO2ABCD";
String pattern = "([A-Z][a-z]*)(((?=[A-Z][a-z]*|$))|\\d+)";

Pattern r = Pattern.compile(pattern);

Matcher m = r.matcher(line);

while (m.find( )) {
     System.out.print(m.group(1));
     if (m.group(2).length() == 0) {
         System.out.println(" 1");
     } else {
         System.out.println(" " + m.group(2));
     }
  }

IDEONE DEMO 

1
rock321987

Vous pouvez utiliser deux modèles: 

  • [0-9]
  • [a-zA-Z]

Split deux fois par chacun d'eux.

List<String> letters = Arrays.asList(test.split("[0-9]"));
List<String> numbers = Arrays.asList(test.split("[a-zA-Z]"))
            .stream()
            .filter(s -> !s.equals(""))
            .collect(Collectors.toList());

if(letters.size() != numbers.size()){
        numbers.add("1");
    }
0
abyversin

Je l'ai fait comme suit

ArrayList<Integer> integerCharacters = new ArrayList();
ArrayList<String> stringCharacters = new ArrayList<>();

String value = "C3H20IO"; //Your value 
String[] strSplitted = value.split("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)"); //Split numeric and strings

for(int i=0; i<strSplitted.length; i++){

    if (Character.isLetter(strSplitted[i].charAt(0))){
        stringCharacters.add(strSplitted[i]); //If string then add to strings array
    }
    else{
        integerCharacters.add(Integer.parseInt(strSplitted[i])); //else add to integer array
    }
}
0
Shree Krishna

Vous pouvez diviser la chaîne en utilisant une expression régulière telle que (? <=\D) (? =\D). Essaye ça :

String alphanum= "abcd1234";
String[] part = alphanum.split("(?<=\\D)(?=\\d)");
System.out.println(part[0]);
System.out.println(part[1]);

va sortir

abcd 1234

0
Karthika