Tag: java

Parse key value separated by ;

Parse key value separated by ;


Let us use as a sample the following string (the 3 dots mean the same pattern to the infinity):


While doing some code review the previous string was parsed using the split method from String class using the “;” character, after that operation another operation was performed on the token “key=value” string (yes, by the “=” sign) and checking that the key was present with an optional value.

I will not type that code here. The code we are interested here is how to parse this pattern using a unique Regular Expression, in Java that regular expression (and other programming language) is as follows:


That would read (without the back references):

  • Match a word character between one and unlimited times
  • Followed by the “=” character
  • Followed by another word character between zero and unlimited times (optional)
  • This is the interesting part. We will use for this regex a positive lookahead (see my other post related to this topic). This means we are interested to match “;” without making “;” part of the match, it is only there to assert that the match of type “key=value” is true.
  • The last “?” at the end of the regex mean that it is optional, this will help to match a string that does not have a “;” at the end of the string, e.g.


As you can see the implementation is straight, if the string matches each captured token is in the group 2 and 3.

public final class KeyValueParser {

private static final ThreadLocal<Pattern> PATTERN_THREAD_LOCAL = ThreadLocal.withInitial(() -> Pattern.compile("((\\w+)=(\\w*)(?=;)?)"));

 * Example on how to use the PATTERN_THREAD_LOCAL declared above.
 * @param paramsAttrValue a String in the form: key0=value0;key1=value1;key2=value2;keyN=valueN......
 * @return a List with Something key value pair
 public static List<Something> getRequestParams(String paramsAttrValue) {
 List<Something> somethings = new ArrayList<>();
 Matcher regexMatcher = PATTERN_THREAD_LOCAL.get().matcher(paramsAttrValue);
 while (regexMatcher.find()) {
    final String key = regexMatcher.group(2) 
    final String value = regexMatcher.group(3);
    //Do something with key and value
    //Probably Something is a holder for the key and the value.
  return somethings;

 * Forbidden to create instances of this class.
 private KeyValueParser() {
   //Forbidden to create instances of this class.


ThreadLocal for the Pattern seems not needed as Pattern is already thread safe.

Google Parser to (now vCard), version 3.0

Google Parser to (now vCard), version 3.0


I have not dedicated time to the Google Address Book converter, only the Alpine part was done, but today I decided to also include the converter for vCard (v2.1), seems working fine in Mozilla Thunderbird when I import the generated file.

Shortly the code (only of the converter)

package at.mavila.gcontactsalp.converters;

import at.mavila.gcontactsalp.pojos.AddressBook;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

 * Converts the List of Address book to a CharSequence.
 * Created by mavila on 4/16/17.
public class VisitCardConverter implements Converter<List<AddressBook>, CharSequence> {

 private static final Pattern NAME_SPLIT = Pattern.compile("(.+)(\\s+)(.+)");

 public CharSequence convert(final List<AddressBook> addressBooks) {

 if (addressBooks == null || addressBooks.isEmpty()) {
 return StringUtils.EMPTY;

 final StringBuilder stringBuilder = new StringBuilder();

 addressBooks.stream().filter(addressBook -> addressBook != null).forEach(addressBook -> {



 final AtomicInteger atomicInteger = new AtomicInteger(1);
 addressBook.getAddress().forEach(emailAddress -> stringBuilder.append("email;internet;" + (atomicInteger.getAndIncrement() == 1 ? "HOME:" : "WORK:")).append(emailAddress).append("\r\n"));

 if (!addressBook.getComment().contains("Google")) {


 return stringBuilder.toString();

 private String createN(final String fullName) {

 if (StringUtils.isEmpty(fullName)) {
 return StringUtils.EMPTY;

 final Matcher matcher = NAME_SPLIT.matcher(fullName);

 if (matcher.find()) {
 return matcher.group(3) + ";" + matcher.group(1);

 return fullName+";";


The list of Address book is already parsed by the SAX parser, so we just deal with the conversion in


To call it as a web service:

curl localhost:8080/importVCard -d @mutt.xml --header "Content-Type:text/xml" > vas.vcf

Where mutt.xml is produced by the Google dump command, see my other post related.

Grab the code from: