Manipulate strings in mongodb that match the regex search - java

In java this is possible
public static void main(String[] args) {
Matcher m = Pattern .compile("^(.*?[.].*?[.].*?[.].*?)[.].*")
.matcher(
"com.SEM.Google.Generico.space.test");
if (m.matches()) {
System.out.println(m.group(1));
}
}
This would give me as result: com.SEM.Google.Generico
If I have a string in mongodb
"dv" : "com.SEM.Google.Generico.space.test"
can I use the mongo aggregation framework somehow to get com.SEM.Google.Generico as result?
It should be as generic as possible. So not something like
$project: {
pathString: {
$substr: ["$path.dv", 0, 23]
}
}
Is this possible at all?
Thanks.

No, there is no way to do this.
This feature has been requested two years ago, but it hasn't been implemented yet ( see the open jira issue: https://jira.mongodb.org/browse/SERVER-11947 ).
If you don't want to use $substr I guess that you should apply the regex on the query results...

var pattern = "Your Regex Pattern"
db.yourCollectionName.find( { "dv": { $regex: pattern} } )
should produce the desired results

Related

Analog of everyItem() from Hamcrest in AssertJ

Is there analog of everyItem() from Hamcrest in AssertJ?
I have a list of emails and need to do Assertion to check that each email contains substring "alex". Currently the only way I can do it with AssertJ is as follows:
List<String> actual = Arrays.asList("alex#gmail.com", "alex1#gmail.com", "ale2#hotmail.com", "bred#gmail.com");
SoftAssertions softly = new SoftAssertions();
for(String email: actual ) {
softly.assertThat(email).contains("alex");
}
softly.assertAll();
Can be done without Soft Assertions there as well, but I'd prefer to check all the item of the list.
Is there any more compact way to do so? To be specific, is there a way in AssertJ to check each item of the list to match a substring?
In Hamcrest I can do it in one line:
assertThat(actual, everyItem(containsString("alex")));
But in AssertJ looks like in any way I have to manually iterate through the list.
Assertj 3.6.0 introduced the allSatisfy assertion, which allows you to perform scoped assertions on each element of the iterable.
Therefore you could do what you want with
assertThat(actual).allSatisfy(elem -> assertThat(elem).contains("alex"));
I found 2 solutions:
1) use java 8
actual.forEach( val -> softly.assertThat(val).contains("alex"));
2) make an utility class
public class AssertUtils {
public static Condition<String> ContainsCondition(String val) {
return new Condition<String>() {
#Override
public boolean matches(String value) {
return value.contains(val);
}
};
}
}
and use it:
softly.assertThat(actual).are(AssertUtils.ContainsCondition("alex"));
You can build AssertJ condition with predicate and use are/have assertion:
#Test
public void condition_built_with_predicate_example() {
Condition<String> fairyTale = new Condition<String>(s -> s.startsWith("Once upon a time"), "a %s tale", "fairy");
String littleRedCap = "Once upon a time there was a dear little girl ...";
String cindirella = "Once upon a time there was a ...";
assertThat(asList(littleRedCap, cindirella)).are(fairyTale);
}
Edit: As pointed by Dan I would now use allSatisfy.
I prefer to use this form of allMatch as follow:
assertThat(movies).extracting("title").allMatch(s -> s.toString().contains("the"));
I just rely on Java 8 stream functionality for that kind of stuff:
assertThat(actual.stream().allMatch(s -> s.contains("alex"))).isTrue();

One line check if String contains bannedSubstrings

I have a String title and a List<String> bannedSubstrings. Now I want to perform a one line check if title is free of those bannedSubstrings.
My approach:
if(bannedSubstrings.stream().filter(bannedSubstring -> title.contains(bannedSubstring)).isEmpty()){
...
}
Unfortunately, there is no isEmpty() method for streams. So how would you solve the problem? Is there a one line solution?
Sounds like you want to read up on anyMatch:
if (bannedSubstrings.stream().anyMatch(title::contains)) {
// bad words!
}
Inversely, there's also noneMatch:
if (bannedSubstrings.stream().noneMatch(title::contains)) {
// no bad words :D
}
This isn't very efficient if title is a long string (but titles usually aren't supposed to be long, I suppose).
If you want an efficient solution and you have many bannedSubstrings, I guess, it would be faster to join them into single regexp like this:
Pattern badWords = Pattern.compile(bannedSubstrings.stream().map(Pattern::quote)
.collect(Collectors.joining("|")));
Then use it like this:
if (badWords.matcher(title).find()) {
...
}
This should build a prefix tree from your substrings, so scanning will be significantly faster. If performance is not the concern in your case, use other answers.
I suppose you are looking for something like this:
if(bannedSubstrings.stream().anyMatch(title::contains)){
}
The answer you've selected is pretty good, but for real performance you'd probably be better off pre-compiling the list of bad words into a regex.
public class BannedWordChecker {
public final Pattern bannedWords;
public BannedWordChecker(Collection<String> bannedWords) {
this.bannedWords =
Pattern.compile(
bannedWords.stream()
.map(Pattern::quote)
.collect(Collectors.joining("|")));
}
public boolean containsBannedWords(String string) {
return bannedWords.matcher(string).find();
}
}

find from array of patterns and run a method

Hey I'm in a bit of trouble.
I need to check for about 200 regex patterns in a string, and according to the pattern found to run a method.
Meaning something like (semi-psuedo):
Pattern pattern = Pattern.compile([Array of patterns]);
Matcher matcher = pattern.matcher(str);
while (matcher.find()) {
Pattern p = matcher.pattern();
p.runSomeMethod();
}
Obviously, the above code is not the way to do it, just trying to clear what I need.
My problem is, to achive that I'd have to extend either String or Pattern, and the real problem is that they're both final so I can't do that.
Basically what I'm trying to do is look for multiple patterns in a string, when only 1 would fit, and run a procedure based on the pattern chosen, trying to avoid a huge switch case I though I'd just implement multiple classes that the pattern will return an object of my class and i'll just run it's method.
Any ideas how can I achive that? I found very little information on the subject.
One way to achieve this is by using the strategy pattern in combination with anonymous inner classes, like this:
private Map<Pattern, Runnable> patterns;
{
{
patterns = new LinkedHashMap<Pattern, Runnable>();
patterns.put(Pattern.compile("\\w+"), new Runnable() { public void run() { System.out.println("word"); } });
patterns.put(Pattern.compile("\\d+"), new Runnable() { public void run() { System.out.println("number"); } });
}
}
public void matchAndExecute(String str) {
Iterator<Entry<Pattern, Runnable>> it = patterns.entrySet().iterator();
while (it.hasNext()) {
Entry<Pattern, Runnable> pattern = it.next();
if (pattern.getKey().matcher(str).matches()) {
pattern.getValue().run();
}
}
}
You don't need Map for this, just create a class holding both Pattern and Runnable and fill a List (or an array) according to your needs.
class PatternMatcher {
private Pattern pattern;
private Runnable runnable;
public PatternMatcher(PatternMatcher pattern, Runnable runnable) {
this.pattern=pattern;
this.runnable=runnable;
}
public boolean apply(String s) {
if (pattern.matcher(s).matches()) {
runnable.run();
return true;}
} else {
return false;
}
}
}
and then use it:
PatternMatcher[] pm = {
new PatternMatcher(...),
new PatternMatcher(...),
...
};
for (PatternMatcher matcher: pm) {
matcher.apply(s);
}
If you want to stop after the first matching pattern is found, use this loop:
for (PatternMatcher matcher: pm) {
if (matcher.apply(s)) {
break;
}
}
EDIT: corrected variable names
What about creating a (LinkedHash)Map with keys for the Patterns and Runnable/Callable for the things to do? Would that work for you? That way you would visit the map and execute the value if the key matches/found.
you should look at strategy pattern.
You can implement an interface and based on the pattern matching you can call the appropriate method.
Usually to create the right instance without revealing the logic try 'Factory Pattern' though you will have to write your logic there
http://www.dotnetperls.com/factory

How to use regular expression for fetching specific data?

I have input stream with the following data:
---------------------------------------------
manil#manil-ubvm:~$ db2level
DB21085I Instance "manil" uses "64" bits and DB2 code release "SQL10010" with
level identifier "0201010E".
Informational tokens are "DB2 v10.1.0.0", "s120403", "LINUXAMD64101", and Fix
Pack "0".
Product is installed at "/home/manil/sqllib".
---------------------------------------------
From above i need v10.1.0.0 to be stored in a string variable.
How to do that using java regular expression?
Use something like this to capture the version pattern :
import java.util.regex.*;
public class RTest {
public static void main(String [] args) {
String raw_data = "asdkgjasdbf984 sdkjfashfiu 4qwsadkfjnv w98sa-asdf08gywbfsd v1231.123.12.11.1 fkjsdfn9823isd";
Pattern version_find = Pattern.compile("v[\\d+\\.?]+");
Pattern directory_find = Pattern.compile("[\\/[^\\/]+]+");
Matcher version_finder = version_find.matcher(raw_data);
while(version_finder.find()) {
System.out.println(version_finder.group());
}
}
}
Output is :
v1231.123.12.11.1
/isd/asdasd2903 ajshdaq09r34/adsj 38/
You really need to understand regexes deeply if you are a programmer. They are one of the essentials. They are hard at first, but once you 'crack them' you don't forget it. Like riding a bike.
This will suit your needs:
String version = yourLine.replaceAll(".*(v\\d+([.]\\d+){3}).*", "$1")
You dont need regularExpression here
just use
String .contain() method and String substring()

Java Cut Links from shoutcast stream url

the string
[playlist]numberofentries=2File1=http://66.162.107.142/cpr1_K128OV.oggTitle1=KCFR NewsLength1=-1File2=http://66.162.107.141:8000/cpr1_K128OV.oggTitle2=KCFR News BackupLength2=-1Version=2
i wanna cut all of the links in this file, how to?
The following class
package regexpso;
import java.util.regex.*;
public class Main {
public static void main(String[] args) {
Pattern p = Pattern.compile("(http:.*?.ogg)");
Matcher m = p.matcher("[playlist]numberofentries=2File1=http://66.162.107.142/cpr1_K128OV.oggTitle1=KCFR NewsLength1=-1File2=http://66.162.107.141:8000/cpr1_K128OV.oggTitle2=KCFR News BackupLength2=-1Version=2");
while (m.find()) {
System.out.println(m.group());
}
}
}
prints
http://66.162.107.142/cpr1_K128OV.ogg
http://66.162.107.141:8000/cpr1_K128OV.ogg
as result.
Use a regular expression to find and replace the URLs. Be aware this sort of thing is fraught with peril. Post an example of what you want the end result to look like for a better answer. Are all the URLs IP addresses?

Categories

Resources