How to write a redis scan command to match either of two patterns - redis

I want to use HSCAN match clause to match a key which is of type 1 or type 2. A regex would be like ^match1|^match2. Is it possible to do this in glob style pattern.

Redis does not offer a straight forward way to match multiple patterns.
Redis matchs using glob-style pattern which is very limited.
Supported glob-style patterns:
h?llo matches hello, hallo and hxllo
h*llo matches hllo and heeeello
h[ae]llo matches hello and hallo, but not hillo
h[^e]llo matches hallo, hbllo, ... but not hello
h[a-b]llo matches hallo and hbllo
Use \ to escape special characters if you want to match them verbatim.

You can't use glob-style for that, but you can Lua your way around this. That means you can use
EVAL and a script (can be similar to https://github.com/itamarhaber/redis-lua-scripts/blob/master/scanregex.lua) for performing the HSCAN match1* first, and then filtering with Lua on match2.*.

Related

How can i query for specific matching substrings while ignoring the rest in a SCAN query?

trying to do a redis SCAN command and trying to figure out how to do glob-pattern substring matching for words instead of single characters (using ruby redis gem)
redis.set("first:url:123", "val1")
redis.set("second:url:123", "val2")
redis.set("third:url:123", "val3")
redis.set("fourth:url:123", "val4")
cursor = 0
pattern = "[first,second]:url:*" ## I only want the first and second keys
redis.scan(cursor, match: pattern)
# => ...
--
according to the docs here i found these available options but it looks like it only works for single characters, how can i use it for words?
h[ae]llo matches hello and hallo, but not hillo
Edit:
https://globster.xyz/
makes me think that using {first,second}:url:123 should work, but that doesnt seem to work either
Redis doesn't support regex expressions for key name patterns, only glob-like expressions.
You can revert to an EVAL Lua script if you are amendment about it. Here's one that does it, but do read the comments: https://gist.github.com/itamarhaber/19c8393f465b62c9cfa8

Redis SCAN matching

If I have the following keys in my Redis:
Person:1234
Person:1234:email
Person:name:John
Person:lastName:Doe
I am trying to only MATCH the first key using SCAN.
I have tried with Person:*, but that of course returns all of them. Person:[^:]* or similar attempts did not work, I tried to match everything excluding the :.
Could someone point me in the right direction?
Redis scan match only support glob style matching. It cannot do regex matching. In order to achieve your goal, you have two options:
Scan all keys and do matching on client side.
Use Lua script to do the scan and matching. You can try the following one-liner as an example:
redis-cli eval 'local res = redis.call("scan", ARGV[1]); local matches = {}; for i,v in ipairs(res[2]) do if v == string.match(v, ARGV[2]) then matches[#matches+1] = v end end res[2] = matches; return res' 0 cursor-starting-from-0 'Person:[^:]*'
This one-liner returns results exactly like the built-in scan command. I'm not a Lua expert, and the code is not fully tested.
Also, Lua's matching is NOT regex matching, although it can solve most problems. You need to take Lua's reference to check if it matches your case.

regex not working correctly when the test is fine

For my database, I have a list of company numbers where some of them start with two letters. I have created a regex which should eliminate these from a query and according to my tests, it should. But when executed, the result still contains the numbers with letters.
Here is my regex, which I've tested on https://www.regexpal.com
([^A-Z+|a-z+].*)
I've tested it against numerous variations such as SC08093, ZC000191 and NI232312 which shouldn't match and don't in the tests, which is fine.
My sql query looks like;
SELECT companyNumber FROM company_data
WHERE companyNumber ~ '([^A-Z+|a-z+].*)' order by companyNumber desc
To summerise, strings like SC08093 should not match as they start with letters.
I've read through the documentation for postgres but I couldn't seem to find anything regarding this. I'm not sure what I'm missing here. Thanks.
The ~ '([^A-Z+|a-z+].*)' does not work because this is a [^A-Z+|a-z+].* regex matching operation that returns true even upon a partial match (regex matching operation does not require full string match, and thus the pattern can match anywhere in the string). [^A-Z+|a-z+].* matches a letter from A to Z, +,|or a letter fromatoz`, and then any amount of any zero or more chars, anywhere inside a string.
You may use
WHERE companyNumber NOT SIMILAR TO '[A-Za-z]{2}%'
See the online demo
Here, NOT SIMILAR TO returns the inverse result of the SIMILAR TO operation. This SIMILAR TO operator accepts patterns that are almost regex patterns, but are also like regular wildcard patterns. NOT SIMILAR TO '[A-Za-z]{2}%' means all records that start with two ASCII letters ([A-Za-z]{2}) and having anything after (%) are NOT returned and all others will be returned. Note that SIMILAR TO requires a full string match, same as LIKE.
Your pattern: [^A-Z+|a-z+].* means "a string where at least some characters are not A-Z" - to extend that to the whole string you would need to use an anchored regex as shown by S-Man (the group defined with (..) isn't really necessary btw)
I would probably use a regex that specifies want the valid pattern is and then use !~ instead.
where company !~ '^[0-9].*$'
^[0-9].*$ means "only consists of numbers" and the !~ means "does not match"
or
where not (company ~ '^[0-9].*$')
Not start with a letter could be done with
WHERE company ~ '^[^A-Za-z].*'
demo: db<>fiddle
The first ^ marks the beginning. The [^A-Za-z] says "no letter" (including small and capital letters).
Edit: Changed [A-z] into the more precise [A-Za-z] (Why is this regex allowing a caret?)

In spacemacs, search occurances of pattern A only in files with name matching pattern B

In spacemacs, I often search for patterns within my project via SPC-* or SPC-/. These commands allow me to input a pattern to search for, such as the name of a function I would like to jump to the definition of.
Sometimes, I would like to restrict that search to files of only a certain type, such as searching only *.elm files and omitting all others (*.hs, *.sql, etc.).
How can I specify filenames for my pattern search?
I.e., How to search for pattern A only in files with name matching pattern B?
I'm wondering if there is some special key I can type as part of my search query to accomplish this.
If you use ag as a search backend, you can do SPC-/ -G<file name regexp> <search pattern>, see man ag for details.
I am not sure if the grep backend can do something similar, I think the internal call to grep is much more complex and adding flags tends to hang my emacs session. From a shell you can run grep -n <search pattern> <file pattern>

Selenium: Part of text present

Is there a way to verify only part of text present?
If there is a text "Warning: A15P09 has not been activated." I need to verify the text is present. However, 'A15P09' is not always the same, so I cannot do something like
Selenium.IsTextPresent("Warning: A15P09 has not been activated.");
I might do something like:
Selenium.IsTextPresent("has not been activated.");
But is there another way to verify this in Selenium. Please let me know if there is.
Thanks!
You could use getText and then do any normal regex that your language supplies for examining that result.
Edit: And for some languages you can do isTextPresent on a pattern modified string. The documentation states:
Various Pattern syntaxes are available
for matching string values:
glob:pattern: Match a string against a
"glob" (aka "wildmat") pattern. "Glob"
is a kind of limited
regular-expression syntax typically
used in command-line shells. In a glob
pattern, "*" represents any sequence
of characters, and "?" represents any
single character. Glob patterns match
against the entire string.
regexp:regexp: Match a string using a
regular-expression. The full power of
JavaScript regular-expressions is
available.
exact:string: Match a
string exactly, verbatim, without any
of that fancy wildcard stuff.
If no
pattern prefix is specified, Selenium
assumes that it's a "glob" pattern.