I receive a user input keyword and want to use it to search my database. I built a query that looks something like this:
db.execute("MATCH (n:User) WHERE n.firstname CONTAINS {keyword} OR n.lastname CONTAINS {keyword} RETURN n.username", params);
But this isn't case sensitive, so I thought of manually building the expression and using regular expressions, sort of as follows:
db.execute("MATCH (n:User) WHERE n.firstname =~ '(?i).*" + keyword + ".*' OR n.lastname =~ '(?i).*" + keyword + ".*' RETURN n.username");
I'm looking either for a function for escaping the regex or a better solution for making the query case-insensitive. Any ideas?
I would suggest storing the properties as all lowercase (or uppercase) and then using the Cypher lower() function to convert user input to lowercase for comparison.
Add lowercase name properties
MATCH (n:User)
SET n.lowerFirstName = lower(n.firstname),
n.lowerLastName = lower(n.lastname)
Find lower case matches based on user input
db.execute("MATCH (n:User) WHERE n.lowerFirstName CONTAINS lower({keyword}) OR n.lowerLastName CONTAINS lower({keyword}) RETURN n.username", params);
Related
I am using Mockrunner to mock Sql DB for my unit tests. Following is my query:-
"select * from table where userId in (" + userIds + ")"
Now my userIds is state dependent. I don't need my test cases dependent on the arrangement inside the list - userIds. So I don't need exact match but regex matching. I have already enabled regex matching by below code:-
StatementResultSetHandler statementHandler = connection.getStatementResultSetHandler();
usersResult = statementHandler.createResultSet("users");
statementHandler.setUseRegularExpressions(true);
//How to write this regex query?
statementHandler.prepareResultSet("select * from table where userId in .*", campaignsResult);
But as it is noted, I have no idea about the regex syntax supported by Mockrunner.
Edit: I unable to match queries like "Select * from tables" with "Select * from tab .*". So It has to do something with the way I using regex with Mockrunner
There are some helpful examples available here. For instance:
public void testCorrectSQL() throws Exception {
MockResultSet result = getStatementResultSetHandler().createResultSet();
getStatementResultSetHandler().prepareResultSet("select.*isbn,.*quantity.*", result);
List orderList = new ArrayList();
orderList.add("1234567890");
orderList.add("1111111111");
Bookstore.order(getJDBCMockObjectFactory().getMockConnection(), orderList);
verifySQLStatementExecuted("select.*isbn,.*quantity.*\\(isbn='1234567890'.*or.*isbn='1111111111'\\)");
}
From this, I surmise that it's using standard Java regex syntax. In which case, you probably want:
prepareResultSet("select \\* from table where userId in \\(.*\\)", campaignsResult);
...or perhaps more succinctly (and depending upon exactly how fine-grained your tests need to be):
prepareResultSet("select .* from table where userId in .*", campaignsResult);
The main caveat to be aware of when enabling the regex matching is that any literal special characters that you want in your query (such as *, (, and ) literals) need to be escaped in your regex before it will work properly.
I want to replace querystring value but it's creating some problems:
Problem 1: Its Removing the "&" symbol after replacing
String queryString = "?pid=1&name=Dell&cid=25";
String nQueryString=queryString.replaceAll("(?<=[?&;])pid=.*?($|[&;])","pid=23");
System.out.println(nQueryString);
output of above example
?pid=23name=Dell&cid=25
you can see its removed the "&" after pid
Problem 2: Its not working if I removed the "?" symbol from the queryString variable.
String queryString = "pid=1&name=Dell&cid=25";
String nQueryString=queryString.replaceAll("(?<=[?&;])pid=.*?($|[&;])","pid=23");
System.out.println(nQueryString);
output of above example
?pid=1&name=Dell&cid=25
We can say the regex is not working, So anyone can suggest me better regex which completely fulfill my requirements.
queryString.replaceAll("(?<=[?&;])pid=.*?(?=[&;])", "pid=23")
Difference is that I'm using a positive-lookahead: (?=[&;]), which is zero-length, making it atomic, and is not actually included in the replacement via replaceAll(), just like your original positive-lookbehind is not replaced.
Alternatively, we can match until a & or ; is found, but not included in the replacement, ie:
queryString.replaceAll("(?<=[?&;])pid=[^&;]*", "pid=23")
[^&;] : ^ negates the following: &;, so [^&;]* will match until a ; or & is encountered.
Yours does not work because ($|[&;]) is a non-atomic group, specifically a capturing group, and thus is included in the replacement. NB: a non-capturing group (?:$|[&;]) would also fail here.
To your final note, you're using a positive look-behind for ?, &, and ;, so by removing the ?, it will no longer match, which makes sense.
Use this regex instead:
String nQueryString = queryString.replaceAll("(?<=[?&;])pid=[^&]*", "pid=23");
//=> ?pid=23&name=Dell&cid=25
Here [^&]* is called negation matching pattern, that will match query string value until & is found OR else end of string is found thus leaving rest of the query string un-effected.
I am doing some string replace in SQL on the fly.
MySQLString = " a.account=b.account ";
MySQLString = " a.accountnum=b.accountnum ";
Now if I do this
MySQLString.replaceAll("account", "account_enc");
the result will be
a.account_enc=b.account_enc
(This is good)
But look at 2nd result
a.account_enc_num=a.account_enc_num
(This is not good it should be a.accountnum_enc=b.accountnum_enc)
Please advise how can I achieve what I want with Java String Replace.
Many Thanks.
From your comment:
Is there anyway to tell in Regex only replace a.account=b.account or a.accountnum=b.accountnum. I do not want accountname to be replace with _enc
If I understand correctly you want to add _enc part only to account or accountnum. To do this you can use
MySQLString = MySQLString.replaceAll("\\baccount(num)?\\b", "$0_enc");
(num)? mean that num is optional so regex will accept account or accountnum
\\b at start mean that there can be no letters, numbers or "_" before account so it wont accept (affect) something like myaccount, or my_account.
\\b at the end will prevent other letters, numbers or "_" after account or accountnum.
It's hard to extrapolate from so few examples, but maybe what you want is:
MySQLString = MySQLString.replaceAll("account\\w*", "$0_enc");
which will append _enc to any sequence of letters, digits, and underscores that starts with account.
try
String s = " a.accountnum=b.accountnum ".replaceAll("(account[^ =]*)", "$1_enc");
it means replace any sequence characters which are not ' ' or '=' which starts the word "account" with the sequence found + "_enc".
$1 is a reference to group 1 in regex; group 1 is the expression in parenthesis (account[^ =]+), i.e. our sequence
See http://docs.oracle.com/javase/7/docs/api/java/util/regex/Pattern.html for details
I see an example of doing a partial string search on the GAE google group (this thread):
String term1 = "cow";
String term2 = "horse";
Query q;
q.setFilter("name.matches('" + term1 + "%')");
so this works like:
"Find all objects of the class where property 'name' starts with term1"
so that would match stuff like:
cowfoo
cowgrok
cowetc
right? I could then replace term1 with term2, and find all instances that begin with 'horse'. Is there a doc that explains this anymore? I just want to check this is how it really works before I make a decision on how to store some strings for my data model,
Thanks
I can't find the docs which present the prefix matching syntax you presented, but your logic is sound. And it looks like the syntax is supported based on the google group message you cited.
For the Python runtime, I would perform a prefix match by using an inequality filter. You can also do this on the Java runtime like this (and this is probably how the % syntax is implemented):
// prefix is some string object
q.setFilter("my_string_field >= :1 && my_string_field < :2");
q.execute(prefix, (prefix + "\ufffd"));
I have a SQL SELECT query which has a LIKE clause containing an underscore, which should specifically look for an underscore, not treat it as a wildcard:
SELECT * FROM my_table WHERE name LIKE '_H9%';
I understand that I can change the actual clause to '[_]H9%' for this to work as I expect, but the problem is that this clause is being generated by Hibernate.
Is there a way to configure Hibernate to escape all underscores in all queries in this way? Failing that, is there a way to configure SQL Server (2008 in my case) to not treat underscores as wildcards?
If you're using Criteria to create the query, you can create your own expression which subclasses org.hibernate.criterion.LikeExpression, using one of the protected constructors that takes in 'Character escapeChar', and does substitution in the value for you. Assuming that '!' is a known value that won't be in any search strings (you can pick any you like, I guess), you can just do:
public class EscapingLikeExpression extends LikeExpression {
public EscapingLikeExpression(String propertyName, String value) {
super(propertyName, escapeString(value), '!', false);
}
static String escapeString(String inputString) {
inputString = inputString.replace("_", "!_");
return inputString;
}
}
if there ARE no such characters (that won't appear in your search value as literals) then add the following as the first line of escapeString() to escape those too:
inputString = inputString.replace("!", "!!");
Why can you not do a string replacement on the value? How is this being used so that this is a non-workable solution?