Parsing complex string using regex
My regex skills are not very good and recently a new data element has thrown my parser into a loop
Take the following string
"+USER=Bob Smith-GROUP=Admin+FUNCTION=Read/FUNCTION=Write"
Previously I had the following for my regex : [+开发者_运维百科\\-/]
Which would turn the result into
USER=Bob Smith
GROUP=Admin FUNCTION=Read FUNCTION=Write FUNCTION=ReadBut now I have values with dashes in them which is causing bad output
New string looks like "+USER=Bob Smith-GROUP=Admin+FUNCTION=Read/FUNCTION=Write/FUNCTION=Read-Write"
Which gives me the following result , and breaks the key = value structure.
USER=Bob Smith
GROUP=Admin FUNCTION=Read FUNCTION=Write FUNCTION=Read WriteCan someone help me formulate a valid regex for handling this or point me to some key / value examples. Basically I need to be able to handle + - / signs in order to get combinations.
You didn't specify what regex engine you're using, but this works if you've got lookahead/lookbehind.
It works on the premise that the keys are all uppercase only, whilst the values aren't - not sure if that's a valid assumption, but if it's not then as noted things will get complicated and messy.
(?<=[+-\/])[A-Z]+=(?:(?![A-Z]+=)[^=])+(?=[+-\/]|$)
And here's my attempt to explain that (not sure how much this makes sense):
(?x) # enable regex comment mode
(?<=[+-\/]) # start with one of the delimiters, but excluded from match
[A-Z]+ # match one or more uppercase (for the key)
= # match the equal sign
(?: # start non-capturing group
(?! # start negative lookahead, to prevent keys matching
[A-Z]+= # a key and equals (since in negative lookahead, this is what we exclude)
) # end the negative lookahead
[^=] # match a character that's not =
)+ # end non-capturing group, match one or more times, until...
(?=[+-\/]|$) # next char must be delimiter or end of line for match to succeed
For Java string->regex, backslashes need escaping (as would quotes, if there were any):
Pattern p = Pattern.compile("(?<=[+-\\/])[A-Z]+=(?:(?![A-Z]+=)[^=])+(?=[+-\\/]|$)");
And if capturing groups are needed, just add parens round the appropriate parts:
Pattern p = Pattern.compile("(?<=[+-\\/])([A-Z]+)=((?:(?![A-Z]+=)[^=])+(?=[+-\\/]|$))");
The matching part of this, to turn it into newline delimited text, is something like...
Matcher m = p.Matcher( InputText );
StringBuffer Result = new StringBuffer("");
while ( m.find() )
{
Result.append( m.Group() + "\n" );
}
Based on your second example, this regex: (\w+)=([\w|-|\s]+)
returns these results:
USER=Bob Smith
GROUP=Admin
FUNCTION=Read
FUNCTION=Write
FUNCTION=Read-Write
The parenthesis provide groupings for each element, so each match will contain two groups, the first will have the part before the = (so USER,GROUP,FUNCTION) and the second will have the value (Bob Smith, Admin, Read, Write, Read-Write)
You can also name the groups if that would make it easier:
(?<funcrion>\w+)=(?<value>[\w|-|\s]+)
Or if you don't care about the groups, you can remove the parens altogether
\w+=[\w|-|\s]+
Another option, if you've got a limited set of keys, you could just match:
(?<=[+-\\/])(USER|GROUP|FUNCTION)=[^=]+(?=$|[+-\\/](?:USER|GROUP|FUNCTION))
Which in Java I'd probably implement like this:
String Key = "USER|GROUP|FUNCTION" ;
String Delim = "[+-\\/]";
Pattern p = Pattern.compile("(?<="+Delim+")("+Key+")=[^=]+(?=$|"+Delim+"(?:"+Key+"))");
This relies on, for example "Write" not being a valid key (and if you can force the case of keys to be either "write" or "WRITE" then that means it'll work).
The matching part of this, to turn it into newline delimited text, is something like...
Matcher m = p.Matcher( InputText );
StringBuffer Result = new StringBuffer("");
while ( m.find() )
{
Result.append( m.Group() + "\n" );
}
If you're delimiting fields with characters that can appear in values, you're screwed.
Suppose you receive a string like:
one=a-two=b-three=c-d-four=e
Should that parse into this?
one=a
two=b
three=c-d
four=e
Or should it parse into this?
one=a
two=b
three=c
d-four=e
How do you know? What's your basis for deciding this?
精彩评论