views:

388

answers:

3

I have config.properties file containing properties in Java Properties format. I need to replace the value of a property with a known name with a new value. The comments and formatting of the file should be preserved.

My current approach is to use RegEx to match the property name and then replace its value. However, Java Properties supports multi-line values, which I have hard time matching.

Here is an example. Suppose config.properties contains the following text:

# A property
A = 1\
     2

# B property
B = 2

I would like to replace the value of property A with "3". The end result should be:

# A property
A = 3

# B property
B = 2

My current RegEx (?s)(A[\\s]*=[\\s]*)(.*) does not work correctly.

Please suggest a RegEx or an a different way of doing this.

Thanks!

+1  A: 

You have tools in Java to load, read, modify and save properties files.

Personally I like Jakarta Commons Configuration.

streetpc
That's definitively a much better approach.
slipset
Does it keep comments and formatting intact like he needs?
Michael Myers
A: 

I agree with streetpc on using Jakarta Commons Configuration.

However to focus on your regex, the problem is that most of the regex engines work on a line per line basis by default.

For example in the (quite old) Perl5Util class (see http://jakarta.apache.org/oro/api/org/apache/oro/text/perl/Perl5Util.html) you can read that patterns have following syntax :

[m]/pattern/[i][m][s][x]

The m prefix is optional and the meaning of the optional trailing options are:

i    case insensitive match 
m    treat the input as consisting of multiple lines 
s    treat the input as consisting of a single line 
x    enable extended expression syntax incorporating whitespace and comments
zim2001
The names of the /m and /s modifiers are misleading; all they do is alter the behavior of the '^', '$' and '.' metacharacters. Whether you apply a regex to a whole file or to one line at a time is entirely up to you.
Alan Moore
A: 

Try this:

String regex = "(?m)^(A\\s*+=\\s*+)"
    + "(?:[^\r\n\\\\]++|\\\\(?:\r?\n|\r|.))*+$";

I left the first part as you wrote it so I could concentrate on matching the value; the rules governing the key and separator are actually much more complicated than that.

The value consists of zero or more of any character except carriage return, linefeed or backslash, or a backslash followed by a line separator or any single non-line-separator character. The line separator can be any of the three most common forms: DOS/Windows (\r\n), Unix/Linux/OSX (\n) or pre-OSX Mac (\r).

Note that the regex is in multiline mode so the line anchors will work, but not singleline (DOTALL) mode. I also used possessive quantifiers throughout because I know backtracking will never be useful.

Alan Moore