Vraag Java - Splits reeks op nummer en letters


Dus ik heb bijvoorbeeld een reeks zoals deze C3H20IO

Wat ik wil doen is deze reeks splitsen zodat ik het volgende krijg:

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

De 1 als het derde element van de Array2 is indicatief voor de monoatomaire aard van de I element. Hetzelfde geldt voor O. Dat is eigenlijk het deel waar ik mee worstel.

Dit is een chemische vergelijking, dus ik moet de elementen scheiden op basis van hun naam en de hoeveelheid atomen die er zijn, etc.


11
2018-04-05 10:21


oorsprong


antwoorden:


Je zou deze aanpak kunnen proberen:

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

Output:

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

Nu zijn alle even indices (0, 2, 4 ...) atomen en oneven zijn het bijbehorende nummer:

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

Output:

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


8
2018-04-05 10:53



U kunt een reguliere expressie gebruiken om over uw invoer te schuiven met behulp van de Matcher.find () methode.

Hier een globaal voorbeeld van hoe het eruit kan zien:

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

Ik weet het, de conversie van List naar Array ontbreekt, maar het zou je een idee moeten geven van hoe je je probleem moet aanpakken.


4
2018-04-05 11:13



Een aanpak zonder REGEX en gegevens die zijn opgeslagen met 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);

OUTPUT:

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

4
2018-04-05 11:20



Dit werkt, ervan uitgaande dat elk element begint met een hoofdletter, dat wil zeggen als je "Fe" hebt, representeer je het niet in String als "FE". In principe splitst u de tekenreeks op elke hoofdletter en splitst u elke nieuwe reeks op letters en cijfers, waarbij u "1" toevoegt als de nieuwe splitsing geen cijfers bevat.

        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
2018-04-05 10:43



make (voor loop) met de grootte van de invoerlengte en voeg de volgende voorwaarde toe

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

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

1
2018-04-05 10:31



Ik stel voor te splitsen met een hoofdletter met look-and-trace regex met een vrije breedte (om items als uit te pakken) C12, O2, Si), splitst vervolgens elk item in het element en het numerieke gewicht ervan:

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
2018-04-05 10:37



Is dit goed? (Niet gebruiken 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));
     }
  }

IDEEN DEMO 


1
2018-04-05 10:54



U kunt de tekenreeks splitsen door een reguliere expressie te gebruiken zoals (? <= \ D) (? = \ D). Probeer dit :

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

zal uitvoeren

abcd 1234


0
2018-04-05 10:29