Java regex and/or string magic to extract IDs from String - java

I have a Java app that is hitting a 3rd party RESTful web service that is returning the following JSON:
{"fizz":
{"widgets":
[
{
"widget_id":"295874"
},
{
"widget_id":"295873"
},
{
"widget_id":"295872"
}
],
"otime":1361993756
},
"resp":"ok"
}
Normally I would use GSON or Genson to map this back to a Java POJO, but this is the only area of the code where I have to do this and I want to be lazy here ;-).
I'm trying to come up with a nifty method that extracts the 3 widget_id values (, and `) and returns them as aList`:
public List<Long> extractIdsFromJson(String json) {
// Can I solve this with a regex perhaps?
}
Not sure what the right approach is - regex, replaceAll, something else? Thanks in advance.

Being lazy here will just bite you in the long run. Parse the JSON and extract the values that way; the 'effort' involved will be less, the code will be more understandable, and future code maintainers will not curse your name.

// untested
public List<Long> extractIdsFromJson(String json) {
List<Long> list = new ArrayList<Long>();
Matcher matcher = Pattern.compile("\"widget_id\":\"?(\\d+)\"?").matcher(json);
while (matcher.find())
list.add(Long.valueOf(matcher.group(1)));
return list;
}

If you like being lazy. Here is the solution. I hope you know whatever entails your choice of solving the problem with regex:
It doesn't check for the structure of the JSON. You ignore the fact that the JSON may be malformed and just blindly extract the data.
It works here since you want a property whose value is not an Object or Array.
RAW regex:
"widget_id"\s*:\s*"(\d+)"
In literal string:
"\"widget_id\"\\s*:\\s*\"(\\d+)\""
Use the regex above with Matcher loop:
Pattern p = Pattern.compile("\"widget_id\"\\s*:\\s*\"(\\d+)\"");
Matcher m = p.matcher(inputString);
while (m.find()) {
System.out.println(m.group(1));
}

Related

how to use Java to replace String?(regex)

I hava one jsonString
String target = "[{"nickName":"andy","password":"wei","userword":"weitest32123"}]";
I wish to get
String target = "[{"nickName":"andy","password":"xxx","userword":"xxx"}]";
I want to use the java String method replaceall(regex,"xxx");
how do?
Try this.
String input = "[{\"nickName\":\"andy\",\"password\":\"wei\",\"userword\":\"weitest32123\"}]";
String output = input.replaceAll("(?<=\"(pass|user)word\":\")[^\"]+", "xxx");
System.out.println(output);
output:
[{"nickName":"andy","password":"xxx","userword":"xxx"}]
You can do it with the Positive Lookbehind regexp regex101.com:
public static void main(String... args) {
String str = "\"[{\"nickName\":\"andy\",\"password\":\"wei\",\"userword\":\"weitest32123\"}]\"";
System.out.println(maskPassword(str)); // "[{"nickName":"andy","password":"xxx","userword":"xxx"}]"
}
public static String maskPassword(String str) {
String regex = "(?<=\"(password|userword)\":)(\"[^\"]+\")";
return str.replaceAll(regex, "\"xxx\"");
}
P.S. I strongly recommend you not to do this with json string. This could follow a problem in the future. It's better to parse this json string into an object and then create json back with modification.
E.g. you can use a tool that I wrote gson-utils
This may seem like you're trying to parse some JSON. I'm not sure if casting it to object and then hiding values would be better approach.
But if you really need to do this way, this would be the solution
// You need this 2 imports
//import java.util.regex.Matcher;
//import java.util.regex.Pattern;
String text = "[{\"nickName\":\"andy\",\"password\":\"wei\",\"userword\":\"weitest32123\"}]";
Pattern pattern = Pattern.compile("\"(?<key>password|userword)\":\"(?<value>.*?)\"");
Matcher matcher = pattern.matcher(text);
String result = matcher.replaceAll("\"${key}\":\"xxx\"");
In Regex you need to specify all keys that you want to mask

Replace a Param in QueryString in Java

lets say I have a url param like token=1234235asdjaklj231k209a&name=sam&firname=Mahan
how can I replace the value of the token with new one ?
I've done something similar to this with pattern and matcher before but I don't recall now
but I know there is a way to do so
Update : the token can contain any letter but &
thanks in advance
Spring has a util that handles this need gracefully. Apache httpcomponents does too. Below is a spring example.
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
public class StackOverflow {
private static class SO46303058 {
public static void main(String[] args) {
final String urlString = "https://subdomain.hostname/path/resource?token=1234235asdjaklj231k209a&name=sam&firname=Mahan";
final URI uri = UriComponentsBuilder.fromHttpUrl(urlString)
.replaceQueryParam("token", "abc")
.build().toUri();
System.out.println(uri);
}
}
}
Don't be afraid of adding dependencies to your project, it beats reinventing the wheel.
We can consider doing a simple regex replacement, with a few caveats (q.v. below the code snippet).
String url = "token=1234235asdjaklj231k209a&name=sam&firname=Mahan";
url = url.replaceFirst("\\btoken=.*?(&|$)", "token=new_value$1");
System.out.println(url);
url = "param1=value&token=1234235asdjaklj231k209a";
url = url.replaceFirst("\\btoken=.*?(&|$)", "token=new_value$1");
System.out.println(url);
Edge cases to consider are first that your token may be the last parameter in the query string. To cover this case, we should check for token=... ending in either an ambersand & or the end of the string. But if we don't use a lookahead, and instead consume that ambersand, we have to also add it back in the replacement. The other edge case, correctly caught by #DodgyCodeException in his comment below, is that there be another query parameter which just happens to end in token. To make sure we are really matching our token parameter, we can preface it with a word boundary in the regex, i.e. use \btoken=... to refer to it.
Output:
token=new_value&name=sam&firname=Mahan
param1=value&token=new_value
make a viewModel.
public class veiwModel(){ String token ; // and get and set for exmample }
then use Gson if u have a json text .
Gson gson = new Gson();
yourViewModel = gson.fronJson(jsonText , viewModel.class);
System.out.println(yourViewModel.getToken());

MongoDB - Java: Not operator and regular expressions

I'm having a problem to convert the next line from my java code to mongoDB:
{ "field1.array": { $not : /\w*(whatever)\w*/ }}.
I've tried to use this:
Criteria criteria = new Criteria() {
#Override
public DBObject getCriteriaObject() {
return
new BasicDBObject("field1.array",
new BasicDBObject("$not",
Pattern.compile(regexp)));
}
};
Which does not work because that sends the regular expression as $regex function which is not compatible with $not operator.
I've tried to negate my regular expression with this: ^((?!my string).)*$
It does not work neither for my array if I don't specify the array position.
Any ideas?
I guess, you just lack the "equals" for the pattern. Never tried with DBObject, but using filters it works like this:
collection.find(
Filters.not(Filters.eq("myField", Pattern.compile("xyz.*")))
)

Generated toString() text from class name

I am devicing an abstract class that will override toString() with an automated message, as such:
public abstract class AbstractTask {
abstract void run();
abstract int calculate();
private String makeMessage() {
String raw = this.getClass().toString();
// do regex stuff here!
}
#Override
public String toString() {
return makeMessage();
}
My implemented (extends AbstractTask) classes might be called something like
TaskXRQMinimize
TaskListParallell
TaskVerifyRepositoryEmpty
TaskCreateXRQs
TaskCreateZRQs
TaskSendAllSRQToTLS
The output I want to have when calling the classes toString() methods are:
Task XRQ Minimize
Task List Parallell
Task Verify Repository Empty
Task Create XRQs
Task Create ZRQs
Task Send All SRQ To TLS
I made a simple regex pattern to find these words:
([A-Z]{1}[a-z]+|[A-Z]{3}[a-z]?)
How do I implement this?
Make your toString() abstract as well, force subclasses to implement it by returning fixed string. Throw away parsing class name and using regular expressions - too fragile and with poor performance. If you really want to make it this way, at least do the computations once per class, not every time toString() is called.
As for the regular expression, I have something better: StringUtils#splitByCharacterTypeCamelCase() from Apache Commons Lang (there is really no need to reinvent some things):
StringUtils.splitByCharacterTypeCamelCase("fooBar") = ["foo", "Bar"]
StringUtils.splitByCharacterTypeCamelCase("foo200Bar") = ["foo", "200", "Bar"]
StringUtils.splitByCharacterTypeCamelCase("ASFRules") = ["ASF", "Rules"]
In your case:
//yields [Task, Send, All, SRQ, To, TLS]
StringUtils.splitByCharacterTypeCamelCase("TaskSendAllSRQToTLS")
you should use something like str.replaceAll("(\\w)([A-Z]\\w)", "$1 $2")
I have not tried this but it looks reasonable. It replaces all sequence like aBc to "a Bc".
this should put you on the right track:
Parts of the regex that you want to extract, surround with (). then
String raw = "TaskXRQMinimize";
String regexp = "([A-Z]{1}[a-z]+)([A-Z]{3})[a-z]?";
Pattern pattern = Pattern.compile(regexp);
Matcher matcher = pattern.matcher(raw);
if (matcher.find())
{
System.out.println("AFSDgaf " + matcher.groupCount());
System.out.println("afdgafd " + matcher.group(1));
System.out.println("afdgafd " + matcher.group(2));
}
I would just iterate on the name of the class and build a new String. the rule is pretty simple: if the current char is upper case and the next is lower case, then you sould insert a space before the current.

How to parse Java properties which contains variables?

I'm loading a file of Java properties which looks like:
transfer_detail = Transfer {0} from {1} to {2} on {3}
After parsing that property I should have String that looks like:
Transfer 200.30 from Debit Account to Credit Account on 2011/01/26
I implemented my self a parser which looks like:
// simplified for brevity
private static String translate(String string, String... replacements){
String result = string;
for(int i = 0; i < replacements.length; i++){
result = result.replace("{"+i+"}", replacements[i]);
}
return result;
}
// and I use it this way:
String result = translate("transaction", "200.30", "Debit Account", etc...);
What I've been wondering is if there's something to do so in the J2SE API. Even for simple things like this I don't like to reinvent the wheel. Do you know any other easier or cleaner way to achieve this?
You want to use the MessageFormat class for filling in the placeholders with actual values.
Don't do that... it's yucky. :)
Use MessageFormat instead.
MessageFormat form = new MessageFormat("Transfer {0} from {1} to {2} on {3}");
System.out.println(form.format(new String[] {
"200.30",
"Debit Account",
"Credit Account",
"2011/01/26"
}));
API MessageFormat doesn't work with messages containing quotes.
You have to manually do the job by using regex for example.

Categories

Resources