简体   繁体   中英

Parsing text using Regex

So I am trying to parse a String that contains two key components. One tells me the timing options, and the other is position.

Here is what the text looks like

KB_H9Oct4GFP_20130305_p00{iiii}t00000{ttt}z001c02.tif

The {iiii} is the position and the {ttt} is the timing options.

I need to separate the {ttt} and {iiii} out so I can get a full file name: example, position 1 and time slice 1 = KB_H9Oct4GFP_20130305_p0000001t000000001z001c02.tif

So far here is how I am parsing them:

    int startTimeSlice = 1;
    int startTile = 1;
    String regexTime = "([^{]*)\\{([t]+)\\}(.*)";
    Pattern patternTime = Pattern.compile(regexTime);       
    Matcher matcherTime = patternTime.matcher(filePattern);

    if (!matcherTime.find() || matcherTime.groupCount() != 3)
    {

        throw new IllegalArgumentException("Incorect filePattern: " + filePattern);
    }

    String timePrefix = matcherTime.group(1);
    int tCount = matcherTime.group(2).length();
    String timeSuffix = matcherTime.group(3);

    String timeMatcher = timePrefix + "%0" + tCount + "d" + timeSuffix;


    String timeFileName = String.format(timeMatcher, startTimeSlice);

    String regex = "([^{]*)\\{([i]+)\\}(.*)";
    Pattern pattern = Pattern.compile(regex);       
    Matcher matcher = pattern.matcher(timeFileName);        



    if (!matcher.find() || matcher.groupCount() != 3)
    {
        throw new IllegalArgumentException("Incorect filePattern: " + filePattern);
    }

    String prefix = matcher.group(1);
    int iCount = matcher.group(2).length();
    String suffix = matcher.group(3);

    String nameMatcher = prefix + "%0" + iCount + "d" + suffix;

    String fileName = String.format(nameMatcher, startTile);

Unfortunately my code is not working and it fails when checking if the second matcher finds anything in timeFileName .

After the first regex check it gets the following as the timeFileName : 000000001z001c02.tif , so it is cutting off the beginning potions including the {iiii}

Unfortunately I cannot assuming which group goes first ( {iiii} or {ttt} ), so I am trying to devise a solution that just handles {ttt} first and then processes {iiii} .

Also, here is another example of valid text that I am also trying to parse: F_{iii}_{ttt}.tif

Steps to follow:

  • Find string {ttt...} in file name
  • Form a number format based on no of "t" in string
  • Find string {iiii...} in file name
  • Form a number format based on no of "i" in string
  • Use String.replace() method to replace time and possition

Here is the code:

String filePattern = "KB_H9Oct4GFP_20130305_p00{iiii}t00000{ttt}z001c02.tif";
int startTimeSlice = 1;
int startTile = 1;

Pattern patternTime = Pattern.compile("(\\{[t]*\\})");
Matcher matcherTime = patternTime.matcher(filePattern);

if (matcherTime.find()) {
    String timePattern = matcherTime.group(0);// {ttt}

    NumberFormat timingFormat = new DecimalFormat(timePattern.replaceAll("t", "0")
            .substring(1, timePattern.length() - 1));// 000

    Pattern patternPosition = Pattern.compile("(\\{[i]*\\})");
    Matcher matcherPosition = patternPosition.matcher(filePattern);

    if (matcherPosition.find()) {
        String positionPattern = matcherPosition.group(0);// {iiii}

        NumberFormat positionFormat = new DecimalFormat(positionPattern
                .replaceAll("i", "0").substring(1, positionPattern.length() - 1));// 0000

        System.out.println(filePattern.replace(timePattern,
                timingFormat.format(startTimeSlice)).replace(positionPattern,
                positionFormat.format(startTile)));
    }
}

Your first pattern looks like this:

String regexTime = "([^{]*)\\{([t]+)\\}(.*)";

This finds a string consisting of a sequence of zero or more non- { characters, followed by {t...t} , followed by other characters.

When your input is

KB_H9Oct4GFP_20130305_p00{iiii}t00000{ttt}z001c02.tif

the first substring that matches is

iiii}t00000{ttt}z001c02.tif

The { before the i's can't match, because you told it only to match non- { characters. The result is that when you re-form the string to do the second match, it will start with iiii} and therefore won't match {iiii} like you're trying to do.

When you're looking for {ttt...} , I don't see any reason to exclude { or any other character from the first part of the string. So changing the regex to

"^(.*)\\{(t+\\}(.*)$"

may be a simple way to fix this. Note that if you want to make sure you include the entire beginning of the string and the entire end of the string in your groups, you should include ^ and $ to match the beginning and end of the string, respectively; otherwise the matcher engine may decide not to include everything. In this case, it won't, but it's a good habit to get into anyway, because that makes things explicit and doesn't require anyone to know the difference between "greedy" and "reluctant" matching. Or use matches() instead of find() , since matches() automatically tries to match the entire string.

Okay, so after a bit of testing I found a way to handle the case:

For parsing the {ttt} I can use the regex: (.*)\\\\{t([t]+)\\\\}(.*)

Now this means I have to increment tCount by one to account for the t I grab from \\\\{t

Same goes for {iii} : (.*)\\\\{i([i]+)\\\\}(.*)

Perhaps an easier way to do this (as confirmed by http://regex101.com/r/vG7kY7 ) is

(\{i+\}).*(\{t+\})

You don't need the [] around a single character you are matching. Keep it simple. i+ means "one or more i 's", and as long as these are in the order given, this expression will work (with the first match being {iiii} and the second {ttttt} ).

You may need to escape the backslash when writing it in a string...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM