1

I am no friend of questions without any code but I have absolutely no idea how to search for this issue.

I got a String like this with a couple of key/value pairs: test=39&test2=4&test3=10

and an update String like test2=5

now I want to call the String.replaceAll method with an expression that replaces the above String with test2=5 so I get test=39&test2=5&test3=10

String lTest = "test=39&test2=4&test3=10";
String lUpdate = "test2=5";
Assert.assertEquals("test=39&test2=5&test3=10",lTest.replace(lTest,???regex???);

lUpdate can be test or test2 or test3. the value behind the = can be a number between 0 and 1000.

How can I manage this with regular expression?

Thx a lot for your help.

UPDATE!!! this works like a charme(thx to user laune):

@Test
public void test(){
  String lResult = update("test1=1234&test2=4949&test3=1", "test2=42");
  assertEquals("test1=1234&test2=42&test3=1", lResult);

  lResult = update("test1=1234&test2=4949&test3=1", "test3=5");
  assertEquals("test1=1234&test2=4949&test3=5", lResult);

  lResult = update("test1=1234&test2=4949&test3=1", "test1=100");
  assertEquals("test1=100&test2=4949&test3=1", lResult);
}

static String update(String str, String upd) {
  // split to get the keyword and the value
  String[] kwv = upd.split("=");
  // compose the regex
  String regex = "(?<=^|&)" + Pattern.quote(kwv[0]) + "=\\d+";
  return str.replaceAll(regex, upd);
}
nano_nano
  • 12,351
  • 8
  • 55
  • 83
  • `s.replace( "test=39&test2=4&test3=10", "test=39&test2=5&test3=10")` or even `s.replace( "test2=4&", "test2=5&")` would do what you *describe*. If this isn't what you *want*, you'll have to improve your description. (What is variable, what not?) – laune Feb 02 '15 at 20:26
  • Is it always going to be the middle value? – ChiefTwoPencils Feb 02 '15 at 20:28
  • See [Query String Manipulation in Java](http://stackoverflow.com/questions/4128436/query-string-manipulation-in-java) as it looks like you are working with a query string and I dont know JAVA but I know you need something more like an object then a string for this type of data manipulation. – MattSizzle Feb 02 '15 at 20:40

4 Answers4

1

How about something like this

String lTest = "test=39&test2=4&test3=10";
String lUpdate = "test2=5";

String name = lUpdate.split("=")[0]; //test2
lTest = lTest.replaceAll("\\b"+name+"=\\d+", lUpdate); 

Since name will be test2 regex will look like \btest2=\d+.

  • \b is word boundary which will prevent regex engine from matching test2 in Footest2
  • \d+ represents one or more digit so it should be able to match numbers from range 0-1000 as pointed in your question.

In case name in name=value pair could contain some special characters like + or % which could be also regex metacharacteres, you should escape them. Easiest way to do so would be using Pattern.quote(name).
Also non alphabetic characters (or digits) like % will break approach with word boundary \b because \btest2 can be matched also for foo%test2 since % is not considered as word characters. In that case we need more precise test to check if name is placed after & character or start of the string (^). In other words we need to use look-behind (?<=&|^)

So your code can be something like

lTest = lTest.replaceAll("(?<=&|^)"+Pattern.quote(name)+"=\\d+", lUpdate); 
Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • Might also be a good idea to add \Q and \E delimiters around the interpolated variable name for robustness. (Should the variable contain special regex symbols itself). – user268396 Feb 02 '15 at 21:00
  • @user268396 `\Q` and `\E` may also have few problems if name will start with `\E` and end with `\Q` for instance. `Pattern.quote(name)` would be better, but since I don't know if input will come from keybord or from predefined data I decided to skip this part for now. – Pshemo Feb 02 '15 at 21:02
  • Agreed, Pattern.quote() is the way to go. – user268396 Feb 02 '15 at 21:07
  • @user268396 Added to answer but I am not sure if it will be needed, based on "`lUpdate` can be `test` or `test2` or `test3`" from question. – Pshemo Feb 02 '15 at 21:10
  • I regret to say that your solution is inconsistent. You take pains for matching literal magics (like .*?+) in the "keyword", but then you risk lots of non-\w characters such as -:!% which are just as likely to occur. – laune Feb 03 '15 at 06:24
  • @StefanBeike Since our solutions are the same it is kind of strange, but I don't mind :) – Pshemo Feb 03 '15 at 09:30
  • sorry. launes only benefit was to put it in a method... but I give you +1 – nano_nano Feb 03 '15 at 09:32
  • @StefanBeike How you wrap this code is entirely up to you. You can place it in method (static or not), or even in constructor. What is important is what code *does*. But again which answer you want to accept is based on your preference so as long as you pick correct (working) solution I don't mind which one you chose. – Pshemo Feb 03 '15 at 09:37
  • yeah I know I am so sorry – nano_nano Feb 03 '15 at 09:52
1

create a new string which looks like lTest "\n" lUpdate
then use this pattern

^([^=]+)=(\d+)\n(.*?)\1=\d+  

and replace w/

$3$1=$2  

Demo

alpha bravo
  • 7,838
  • 1
  • 19
  • 23
1

You will first have to break down your lUpdate string into the variable name and value, so you can search for the variable name in lTest:

String lTest = "test=39&test2=4&test3=10";
String lUpdate = "test2=5";

Matcher assignmentMatcher = Pattern.compile("(.*)=(.*)").matcher(lUpdate);
if (assignmentMatcher.matches()) {
    String varName = assignmentMatcher.group(1);
    String val = assignmentMatcher.group(2);

    String replaced = lTest.replaceFirst(varName + "=[^&]+", varName + "=" + val);
    Assert.assertEquals("test=39&test2=5&test3=10",replaced);
}
mfk
  • 331
  • 3
  • 4
1

The regex should be constructed from the update string. I use negative lookbehind so that even keywords with, say, an embedded hyphen would work.

static String update( String str, String upd ){
    // split to get the keyword and the value
    String[] kwv = upd.split( "=" );
    // compose the regex
    String regex = "(?<=^|&)" + Pattern.quote(kwv[0]) + "=\\d+";
    return str.replaceAll( regex, upd );
}
laune
  • 31,114
  • 3
  • 29
  • 42