how to use positioning/range in regexp - sql

I have a product code where the references always follows this pattern: XX00XX000XX. Characters 1 and 2 are always a combination of 2 letters, 3 to 4 a combination of 2 numbers, 5 to 6 letters, 7 to 10 numbers and 10 to 11 letters again (they`re always varying so it'll never be the same).
I want to do a regexp_contains (or another variant) that matches by position like; position 1 - 2 must be [[:alpha:]], 3 - 4 [[:digit:]], and so on.
(I need this to find product codes that match the reference pattern inside sell links, but I can't find any clear explanation on how to use positioning on regex statements...)

You can use character classes for this.
[a-zA-Z][a-zA-Z]\d\d[a-zA-Z][a-zA-Z]\d\d\d[a-zA-Z][a-zA-Z]
This regex contains the class [a-zA-Z] and \d, which matches letter and digit respectively. This explicitly checks, first character is a letter, second character is a letter, third character is a digit, etc.
The character classes match 1 character in the set specified, so [a-zA-Z] matches any letter, [13579] will match any odd number, etc.

Related

Regex - trying to get the 5 digit words extracted from the string (presto)

I am trying to retrieved each sequence of 5 numbers / letters that are in brackets just like this example:
accuracy of action - [1232d, 74294, qw23t, 23d45, 76wer, 12874] march
and from that I want to extract 1232d 74294 qw23t 23d45 76wer 12874
I know that to extract only a single 5 digit sequence in square brackets I can do \[[a-z0-9 ]{5,7}\] But I don't know how to do retrieve various 5 digit sequences.
Right now, since all the words inside [...] consist of 5 alphanumeric chars, you can use
(?:\G(?!^),\s*|\[)(\w+)(?=[^\]\[]*])
See the regex demo.
Details:
(?:\G(?!^),\s*|\[) - either the end of the preceding successful match and a comma and zero or more whitesapces, or a [ char
(\w+) - Group 1: one or more word chars
(?=[^\]\[]*]) - followed with zero or more chars other than [ and ] and then a ].

How to extract just numeric value with REGEXP_EXTRACT in BigQuery?

I am trying to extract just the numbers from a particular column in BigQuery.
The fields concerned have this format: value = "Livraison_21J|Relais_19J" or "RELAIS_15 DAY"
I am trying to extract the number of days for each value preceeded by the keyword "Relais".
The days range from 1 to 100.
I used this to do so:
SELECT CAST(REGEXP_EXTRACT(delivery, r"RELAIS_([0-9]+J)") as string) as relayDay
FROM TABLE
I want to be able to extract just the number of days regardless of the the string that comes after the numbers, be it "J" or "DAY".
Sample data :
RETRAIT_2H|LIVRAISON_5J|RELAIS_5J | 5J
LIVRAISON_21J|RELAIS_19J | 19J
LIVRAISON_21J|RELAIS_19J | 19J
RETRAIT_2H|LIVRAISON_3J|RELAIS_3J | 3J
You may use
REGEXP_EXTRACT(delivery, r"(?:.*\D)?(\d+)\s*(?:J|DAY)")
See the regex demo
Details
(?:.*\D)? - an optional non-capturing group that matches 0+ chars other than line break chsrs as many as possible and then a non-digit char (this pattern is required to advance the index to the location right before the last sequence of digits, not the last digit)
(\d+) - Group 1 (just what the REGEXP_EXTRACT returns): one or more digits
\s* - 0+ whitespaces
(?:J|DAY) - J or DAY substrings.

Teradata regular expressions, look behind

I have a field, Simplified_Description and I'm looking for patterns in it. Specifically, I'm looking for a pattern like 6 X 8 or 6X8 or 600X800. I want to pull out the first and second numbers into new fields. I've been able to get the first number (with much help) using a look-ahead.
REGEXP_substr(Simplified_Description, '[0-9]+(?= {0,1}[X] {0,1}[0-9]+)') AS FirstNum,
When I try to get the second number by changing the look-ahead to a look-behind (by simply adding in a "<"),
REGEXP_substr(Simplified_Description, '[0-9]+(?<= {0,1}[X] {0,1}[0-9]+)') AS SecondNum
I now get an error
SELECT Failed. [9134] The pattern specified is not a valid pattern.
I am a complete newb on regular expressions, especially on look-ahead and look-behind, so it's possible I have some extremely simple error, but I can't figure it out as what I'm doing appears to be the correct syntax.
You may use the following regex to extract the first number:
REGEXP_substr(Simplified_Description, '\d+(?=\s*X\s*\d)') AS FirstNum
and this regex for the second number:
REGEXP_substr(Simplified_Description, '\d+\s*X\s*\K\d+') AS SecondNum
See the regex 1 and regex 2 demo.
Patter 1 details
\d+ - 1 or more digits that are followed with...
(?=\s*X\s*\d) - a sequence of patterns:
\s* - 0+ whitespaces
X - an X char
\s* - 0+ whitespaces
\d - a digit.
Pattern 2 details
\d+ - 1 or more digits
\s*X\s* - an X char enclosed with any 0+ whitespace chars
\K - a match reset operator that omits (removes) the text matched so far from the match value
\d+ - 1 or more digits.

regex - match exactly 10 digits with atleast one symbol or spaces between them

I'm trying to write a query in oracle sql to get rows which has invalid 10 digit numbers, ie with other symbols in between them.
For example:
(111) 111-1111 #10 digit number with some symbols and spaces in between
111-111-1111
(111)111-1111
111)111-1111
(111) 11 1-1111
ie, It should match exactly 10 digit numbers which are non consecutive because it has some symbols in it.
So it should not match the following example:
111 #consecutive 3 digit number
11 1 #3 digit number with spaces
11-1 #3 digit number with symbol in between
1111111111 #consective 10 digit number
And I'm using REGEXP_LIKE, something like this
select * from table where REGEXP_LIKE(column, ?)
Any help is much appreciated. Thanks.
You could use a combination of a regex and length; the latter to exclude a pure 10-digit number without other characters:
regexp_like(col, '^[ .()-]*(\d[ .()-]*){10}$') and length(col) > 10
In the [.()-] class you would list all the characters that you would allow as symbols among the digits. Note that - needs to be the last in that list or else be escaped.
If you would allow any non-digit to occur among the 10 digits, you can use \D:
regexp_like(col, '^\D*(\d\D*){10}$') and length(col) > 10
So: the string should have length greater than 10, and the total number of digits must be exactly 10. This can be done without regular expressions (which should make it faster):
... where length(str) > 10 and
length(str) = 10 + length(translate(str, 'z0123456789', 'z'))
translate will translate the letter z to itself and all the other characters (digits) to nothing. Having to include the z is annoying, but unavoidable; translate will return NULL if any of its arguments is NULL. The second condition says the length of the input str is exactly 10 more than the length of the string with all digits removed - so there are exactly 10 digits.

SQL - Create Unique AlphaNumeric based on a 10-digit integer stored as VARCHAR

I'm trying to emulate a function in SQL that a client has produced in Excel. In effect, they have a unique, 10-digit numeric value (VARCHAR) as the primary key in one of their enterprise database systems. Within another database, they require a unique, 5-digit alphanumeric identifier. They want that 5-digit alphanumeric value to be a representation of the 10-digit number. So what they did in excel was to split the 10-digit number into pairs, then convert each of those pairs into a hexadecimal value, then stitch them back together.
The EXCEL equation is:
=IF(VALUE(MID(A2,1,4))>0,DEC2HEX(VALUE(MID(A2,3,2)))&DEC2HEX(VALUE(MID(A2,5,2)))&DEC2HEX(VALUE(MID(A2,7,2)))&DEC2HEX(VALUE(MID(A2,9,2))),DEC2HEX(VALUE(MID(A2,5,2)))&DEC2HEX(VALUE(MID(A2,7,2)))&DEC2HEX((VALUE(MID(A2,9,2)))))
I need the SQL equivalent of this. Of course, should someone out there know a better way to accomplish their goal of "a 5-digit alphanumeric identifier" based off the 10-digit number, I'm all ears.
ADDED 8/2/2011
First of all, thank you to everyone for the replies. Nice to see folks willing to help and even enjoying it! Based on all the responses, I'm apt to tell my client they're intent is sound, only their method is off kilter. I'd also like to recommend a solution. So the challenge remains, just modified slightly:
CHALLENGE: Within SQL, take a 10 digit, unique NUMERIC string and represent it ALPHANUMERICALLY in as few characters as possible. The resulting string must also be unique.
Note that the first 3-4 characters in the 10-digit string are likely to be zeros, and that they could be stripped to shorten the resulting alphanumeric string. Not required, but perhaps helpful.
This problem is inherently impossible. You have a 10 digit numeric value that you want to convert to a 5 digit alphanumeric value. Since there are 10 numeric characters, this means that there are 10^10 = 10 000 000 000 unique values for your 10 digit number. Since there are 36 alphanumeric characters (26 letters + 10 numbers), there are 36^5 = 60 466 176 unique values for your 5 digit number. You cannot map a set of 10 billion elements into a set with around 60 million.
Now, lets take a closer look at what your client's code is doing:
So what they did in excel was to split the 10-digit number into pairs, then convert each of those pairs into a hexadecimal value, then stitch them back together.
This isn't 100% accurate. The excel code never uses the first 2 digits, but performs this operation on the remaining 8. There are two main problems with this algorithm which may not be intuitively obvious:
Two 10 digit numbers can map to the same 5 digit number. Consider the numbers 1000000117 and 1000001701. The last four digits of 1000000117 get mapped to 1 11, where the last four digits of 1000001701 get mapped to 11 1. This causes both to map to 00111.
The 5 digit number may not even end up being 5 digits! For example, 1000001616 gets mapped to 001010.
So, what is a possible solution? Well, if you don't care if that 5 digit number is unique or not, in MySQL you can use something like:
hex(<NUMERIC VALUE> % 0xFFFFF)
The log of 10^10 base 2 is 33.219280948874
> return math.log(10 ^ 10) / math.log(2)
33.219280948874
> = 2 ^ 33.21928
9999993422.9114
So, it takes 34 bits to represent this number. In hex this will take 34/4 = 8.5 characters, much more than 5.
> return math.log(10 ^ 10) / math.log(16)
8.3048202372184
The Excel macro is ignoring the first 4 (or 6) characters of the 10 character string.
You could try encoding in base 36 instead of 16. This will get you to 7 characters or less.
> return math.log(10 ^ 10) / math.log(36)
6.4254860446923
The popular base 64 encoding will get you to 6 characters
> return math.log(10 ^ 10) / math.log(64)
5.5365468248123
Even Ascii85 encoding won't get you down to 5.
> return math.log(10 ^ 10) / math.log(85)
5.1829075929158
You need base 100 to get to 5 characters
> return math.log(10 ^ 10) / math.log(100)
5
There aren't 100 printable ASCII characters, so this is not going to work, as zkhr explained as well, unless you're willing to go beyond ASCII.
I found your question interesting (although I don't claim to know the answer) - I googled a bit for you out of interest and found this which may help you http://dpatrickcaldwell.blogspot.com/2009/05/converting-decimal-to-hexadecimal-with.html