tags:

views:

420

answers:

7
errorString="AxisFault\n
 faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.generalException\n
 faultSubcode: \n
 faultString: My Error\n
 faultActor: \n
 faultNode: \n
 faultDetail: \n
    {}string: this is the fault detail"


Pattern pattern = Pattern.compile(".*faultString(.*)", Pattern.DOTALL);
Matcher matcher = pattern.matcher(errorString);
if (matcher.matches()) {
   String match = matcher.group(1);
   return match;
}

I want to get "My Error", but it returns to the end of the whole string instead of matching to the \n at the end of the faultString line. I've tried many techniques to get it to stop at the end of the line, without success.

thanks

+8  A: 

You shouldn't be passing Pattern.DOTALL; that causes newlines to be matched by .*, which is exactly what you don't want here.

A better regex would be:

Pattern pattern = Pattern.compile("faultString: (.*)");

and then, instead of matcher.matches(), use find() to see if it appears anywhere in the string.

Note also that I've modified the regex to only group the "My Error" part, instead of ": My Error" like your original one would have.

Just to be clear, here is the code I tested:

Pattern pattern = Pattern.compile("faultString: (.*)");
Matcher matcher = pattern.matcher(errorString);
if (matcher.find()) {
    System.out.println(matcher.group(1));
}

where errorString is the same as yours.
The output is:

My Error
Michael Myers
this is what i'm looking for. still curious how to make it work with matches though.
phil swenson
With matches(), you would use ".*faultString: ([^\\n]*).*" with Pattern.DOTALL, as described by Chris Thornhill and Mike Digdon.
Michael Myers
But I prefer not to use extraneous dots if I can help it (see Jan Goyvaerts's article http://www.regular-expressions.info/dot.html ). In this case it won't make a difference, but for future reference, just try to match what you need. (Also, I would prefer to pull the Pattern object out into a static final variable to avoid recompiling it on every invocation.)
Michael Myers
It's important to realize the difference between Matcher.matches() and Matcher.find().The matches method attempts to match the entire input sequence against the pattern. It won't return true unless the pattern matches the entire string from start to end. This is often used with ^ and $ to denote the beginning and end of the string.The find method scans the input sequence looking for the next subsequence that matches the pattern. It will return true if the pattern occurs anywhere in the string.
Sam Barnum
+1  A: 
Pattern pattern = Pattern.compile("^faultString(.*)$", Pattern.MULTILINE);
Chas. Owens
^faultString will cause trouble; it looks like there's a leading space. How about "\\bfaultString: .*$" instead? +1 for Pattern.MULTILINE regardless; that's the key point.
ojrac
Actually, the key point is using find() instead of matches().
Alan Moore
this was one of the approaches I tried. doesn't match.
phil swenson
+1  A: 

This looks like property file format. Would it be easier to load this string into a java.util.Property using StringReader and then reading from it?

Chetan Sastry
i'm trying to force myself to solve string parsing issues by using regex for a while so I can actually learn regular expressions better. i rarely use them, but would like to get better at it.i could solve this problem much faster by other approaches of course, but I want to expand my skillset..
phil swenson
+1  A: 

This works with the .matches() approach:

Pattern pattern = Pattern.compile(".*faultString([^\\n]*).*", Pattern.DOTALL);
Chris Thornhill
+2  A: 

I'd probably clean up Chris's regex to the following: ".*faultString:\\s*([^\\n]*).*"

Mike Digdon
+1  A: 

Keep in mind that regex stuff is expensive. Chetan has the right idea.

Here's some sample code--

    String errorString = "AxisFault\n"
            + "    faultCode: {http://schemas.xmlsoap.org/soap/envelope/}Server.generalException\n"
            + "    faultSubcode: \n" 
            + "    faultString: My Error\n"
            + "    faultActor: \n" 
            + "    faultNode: \n"
            + "    faultDetail: \n"
            + "        {}string: this is the fault detail";

 Properties p = new Properties();
 ByteArrayInputStream bis = new ByteArrayInputStream(errorString
   .getBytes());

 try {
  p.load(bis);
 } catch (IOException e) {

 }

 System.out.println(p.toString());
 System.out.println(p.getProperty("faultString"));
Nathan
I don't think Properties handles delimiters other than '='. Certainly a custom parser could be faster, but one doesn't generally need to worry too much about the performance of error reporting.
Michael Myers
The code runs successfully, so I'm sure it handles colons.
Nathan
the string parsing isn't in a perf sensitive area, so perf isn't important...
phil swenson
A: 

Maybe getFaultString? :)

edit: or ((AxisFault) exception.getRootCause()).getFaultString(). I just thought that you maybe overlooked the fact that you can get that directly from AxisFault itself.

disown
i want to pull several fields.
phil swenson
actually after looking more closely at AxisFault your approach makes more sense. regex is way over-engineering. still a good exercise to mess with the reg ex stuff tho.
phil swenson