如何查找连续重复的未知子字符串

时间:2016-03-29 19:32:14

标签: java string substring

我正在努力建立一个系统,将一个给定的扩展化学公式(例如C6H2NO2NO2NO2CH3)括在括号中(如果该术语在化学中是正确的),使其成为C₆H₂(NO₂)₃CH₃。 (在第一个实例中忽略下标或缺少下标)。问题是,我不知道重复的分子会是什么,甚至不知道它会持续多久。我如何找到并计算重复次数?

对于上下文,这是我的代码到目前为止,它从2D元素列表中生成公式:

private String getFormula(List<List<Element>> elements)
{
    String formula = ""; //TODO Switch out for StringBuilder

    for(List<Element> currentElement : elements)
    {
        formula += currentElement.get(0).getSymbol(); //Every element per list is identical, so looking at 0 will always be safe
        if(currentElement.size() > 1) formula += currentElement.size(); //Only display a number if there is more than 1 element
    }

    return formula;
}

5 个答案:

答案 0 :(得分:2)

This answer提供了代码:String result = source.replaceAll("(.+)\\1+", "$1"),它取代了所有重复的子字符串。

我认为稍微修改一下代码应该做你想要的。如果使用"($1)"作为替换,它将在括号中包装匹配。您可以逐步完成替换,并确定括号后应该出现的数字。

要阻止正则表达式捕获前面的数字,请尝试"([A-Za-z]+[1-9]*)\\1+"

This link解释了如何计算匹配数。它有点复杂:

 Pattern pattern = Pattern.compile("([A-Za-z]+[1-9]*)\\1+");
    Matcher  matcher = pattern.matcher(YOUR_CHEM_STRING);

   int count = 0;
   String prior="";
    while (matcher.find()){
       if(m.group().equals(prior){
             count++;
       }else{
           YOUR_CHEM_STRING.replaceAll("([A-Za-z]+[1-9]*)\\1+","($1)"+count);
           count=0;
       }
    }

答案 1 :(得分:2)

编辑已更新,以便考虑订单。谢谢@JakeStanger!
第二次编辑更新以反映分子以|结束的新情况 我使用正则表达式来分割String,因为从给定的|我们知道新分子在Hashmap之后开始。我使用Hashmap来跟踪每种类型的分子数量。最后,我遍历String result中的每个值,并附加到 public static String factorise(String input) { String result = ""; Map<String, Integer> molecules = new LinkedHashMap<>(); String[] res = input.split("\\|"); for (String t : res) { //Check if we already have this element in our map if (!molecules.containsKey(t)) { //If not then add it and set the count to 1 molecules.put(t, 1); } else { //If we do then update the count by 1 molecules.put(t, molecules.get(t) + 1); } } //Iterate through each molecule for (String key : molecules.keySet()) { if (molecules.get(key) == 1) { //If the count is only at one, then we just need to append it. result += key; } else { //Otherwise, we need the parentheces and the number of repetitions followed after result = result + "(" + key + ")" + molecules.get(key); } } return result; } ,具体取决于它是否是一个分子。干杯!

    System.out.println(factorise("C6|H2|NO2|NO2|NO2|CH3|OH|OH"));
    System.out.println(factorise("HO|HO"));

运行

<script type="text/javascript" src="//cdn.datatables.net/plug-ins/1.10.11/sorting/date-uk.js"></script>

运行时产生以下内容:

  

运行:
  C6H2(NO2)3 CH 3(OH)2
  (HO)2个
  建立成功(总时间:0秒)

答案 2 :(得分:1)

您计算将公式元素拆分为一个列表,然后解析它,计算连续重复次数。当计数大于1时,您将使用括号添加它。

String formula = "C6H2NO2NO2NO2CH3";
Pattern p = Pattern.compile("[a-zA-Z]+[0-9]+");
Matcher m = p.matcher(formula);
List<String> parts = new ArrayList<String>();
while(m.find()) {
    parts.add(m.group());
}

String shrink = "";
int count = 0;
for(int i=0; i<parts.size(); i++) {
    count++;
    if(i+1 == parts.size() || !parts.get(i+1).equals(parts.get(i))) {
        if(count == 1)
            shrink += parts.get(i);
        else
            shrink += "("+parts.get(i)+")"+count;
        count = 0;
    }
}
System.out.println(shrink); // result = "C6H2(NO2)3CH3"

如果您能够发送元素列表,请尝试以下:

public static String shortForumla(List<List<Element>> elements) {
    String shrink = "";
    int count = 0;
    for(int i=0; i<elements.size(); i++) {
        String symbol = elements.get(i).get(0).symbol();
        if(i+1 == elements.size() || !elements.get(i+1).get(0).symbol().equals(symbol)) {
            if(count == 1)
                shrink += symbol;
            else
                shrink += "("+symbol+")"+count;
            count = 0;
        }
    }
    return shrink;
}

答案 3 :(得分:1)

这是一种替代解决方案,它使用简单的字符串解析来查找匹配的重复子字符串。

public static String factorise(String input) {

    StringBuilder result = new StringBuilder();

    for (int start = 0; start < input.length(); start++) {
        char c = input.charAt(start);
        if (c >= '0' && c <= '9') {
            result.append(c);
            continue;
        }

        boolean foundRepeat = false;
        for (int end = start + 1; end <= input.length(); end++) {
            int length = end - start;
            if (end + length > input.length()) break;

            String sub = input.substring(start, end);
            String nextsub = input.substring(end, end + length);
            int nextpos = end + length;
            int count = 1;

            while (sub.equals(nextsub)) {
                count++;
                if (nextpos + length > input.length()) break;

                nextsub = input.substring(nextpos, nextpos + length);
                nextpos += length;
            }

            if (count > 1) {
                result.append("(" + sub + ")" + count);
                start += length * (count) - 1;
                foundRepeat = true;
                break;
            }
        }

        if (!foundRepeat) {
            result.append(c);
        }
    }

    return result.toString();
}

示例:

  • 输入:输出
  • C6H2NO2NO2NO2CH3C6H2(NO2)3CH3
  • CaOHOHCa(OH)2
  • C6H2OH2ONOC6(H2O)2NO
  • C6H2NO2NO2NO2CH3OHOHC6H2(NO2)3CH3(OH)2

答案 4 :(得分:0)

以下是使用Map&amp;的另一种解决方案。 ArrayList代替regex。 我将每个分子插入Map并在每次出现在公式中时增加其键值,并使用ArrayList来维持分子的顺序。

public static void main(String [] audi){
        String s="C66H2NO2NO2NO2CH3";
        Map<String, Integer > Formula=new HashMap<String, Integer >();
        List E = new ArrayList();

        String t="";int c=0,l=s.length();
        for(int i=0;i<l;i++)
        {
            t=t.concat(""+s.charAt(i));
            if(Character.isDigit(s.charAt(i)))
            {
                if(((i+1)<l && !Character.isDigit(s.charAt(i+1)) )|| i==l-1)
                {
                    int count = Formula.containsKey(t) ? Formula.get(t) : 0;
                    Formula.put(t, count + 1);
                    if(!E.contains(t))
                    E.add(t);
                    t="";
                }
            }
        }
        //display
        for(int i=0;i<E.size();i++){
            if(Formula.get(E.get(i))>1)
                System.out.print("("+E.get(i) + ")"+Formula.get(E.get(i)));
            else
                System.out.print(E.get(i));
        }
}

输出: C6H2(NO2)3CH3