Search code examples
javaregexstringdictionarybnd

Java String to Map. Best way to do that


Hi I have a problem that I can't solve. A have exported pacakges from the jar manifest in form of String and I want to put it in Map where key is the name of the package and the rest information in value. You will say that is peace of cake but lets show you what exactly I want to do. I have a String, I little piece from it

 aQute.bnd.annotation;version="1.43.1",aQute.bnd.annotati
 on.component;version="1.43.1",aQute.bnd.annotation.metatype;version="1.
 43.1",aQute.bnd.ant;uses:="aQute.service.reporter,org.apache.tools.ant,
 org.apache.tools.ant.taskdefs,org.apache.tools.ant.types";version="0.0.
 0",aQute.bnd.build;version="2.1.0";uses:="aQute.bnd.maven.support,aQute
 .bnd.osgi,aQute.bnd.service,aQute.bnd.service.action,aQute.bnd.version,
 aQute.service.reporter",aQute.bnd.build.model;version="2.3";uses:="aQut
 e.bnd.build.model.clauses,aQute.bnd.properties,aQute.bnd.version,org.os
 gi.resource",aQute.bnd.build.model.clauses;version=2;uses:="aQute.bnd.h
 eader",aQute.bnd.build.model.conversions;uses:="aQute.bnd.build.model,a
 Qute.bnd.build.model.clauses,aQute.bnd.header,aQute.libg.tuple,org.osgi
 .resource";version="0.0.0"

If I split it on comma(,) in the keys there will be wrong peaces because we have

aQute.bnd.ant;uses:="aQute.service.reporter,org.apache.tools.ant,
 org.apache.tools.ant.taskdefs,org.apache.tools.ant.types";version="0.0.
 0"

where in uses clause we separate the name of the dependent packs with comma too. So the line above have to be in my output map as:

Key: aQute.bnd.ant
Value: uses:="aQute.service.reporter,org.apache.tools.ant,
 org.apache.tools.ant.taskdefs,org.apache.tools.ant.types";version="0.0.
 0"

So which String methods or regex to use to do my work?


Solution

  • //split at , only if it's not within ""
    String[] packages=input.split(",(?=([^\"]*\"[^\"]*\")+[^\"]*$)");
    for(String pack:packages)
    {
        String[] output=pack.split("(?=uses:=)");
        output[0];//key
        if(output.length==2)//incase if there's no value
        output[1];//value
    }
    

    Edit

    (?=uses:=) is a lookahead which would match at the position which is followed by uses:=..Now we could have used uses:= as regex but that would eat uses:=...To avoid it we use zero width lookahead