Python Regex - How to restrict a given regex pattern to a range of character

Viewed 309

I am using python to perform some text analysis and using regex to get required pattern from the text.

I would like to know, how can i restrict a pattern to specified number of characters.

For Eg - We have make use of {a,b} to define lower and upper bound of a specified character. How can the same logic be applied to a full pattern.

I have the following code:

import re
text = '''

547 U18101MH1988PTCO50073 =RAINBOW GARMENTS AND EXPORTS (INDIA) PRI
548 UU24230MH2004PTC147574 RAINBOW HERBAL AND RESEARCH PRIVATE LIMI
549 U55200MH1992PTCO067327 RAINBOW HOLIDAY-INNPVT.LTD.

550 U15100MH2004PTC148619 RAINBOW HORTICULTURE PRIVATE LIMITED

551 US9S99S9MH2000PTC124660 RAINBOW INFOTECH (INDIA) PRIVATE LIMITED
552 U70200MH2011PTC221779 RAINBOW INFRAVENTURES PRIVATE LIMITED
553 U15130MH2004P1C14/013 RAINBOW JELSTAR FOODS PRIVATE LIMITED
'''

re.findall('U.*\d{5}.*\d',text)

This output would give me a list of values from the text. I want to restrict the length of individual values in the list to be between 19 to 21. How can i achieve the result?

Also, out of curiosity, is it possible to get all possible matches in a given text - for eg - UU24230MH2004PTC147574 value can have multiple multiple match possible using the string provided along with the restriction of length as mentioned above?

I know i can achieve some bit of it using list comprehension but want regex to do it for me as i have complex regex query string and this is just a small component of the overall.

Thank you all

3 Answers

We can use a lookahead to assert that the length of the matched string is between 19 and 21 chars long.

(?=\S{19,21}\s)U\S*\d{5}\S*

However, this relies on there being 19-21 chars prior to a white space.

So in the case of UU24230MH2004PTC147574 it would match U24230MH2004PTC147574 and ignore the first U.


re.findall(r'(?=\S{19,21}\s)U\S*\d{5}\S*', text)
#['U18101MH1988PTCO50073', 'U24230MH2004PTC147574', 'U15100MH2004PTC148619', 'U70200MH2011PTC221779', 'U15130MH2004P1C14/013']

Regex101

You can use

(?<!\S)(?=\S{19,21}(?!\S))U\S*\d{5}\S*\d(?!\S)

See the regex demo.

Details:

  • (?<!\S) - left hand whitespace boundary
  • (?=\S{19,21}(?!\S)) - immediately to the right, there must be 19, 20 or 21 non-whitespace chars followed with whitespace or end of string
  • U - an U char
  • \S* - zero or more non-whitespace chars
  • \d{5} - five digits
  • \S* - zero or more non-whitespace chars
  • \d - a digit
  • (?!\S) - immediately to the right, there should be a whitespace or end of string.

See the Python demo:

import re
text = '''
 
547 U18101MH1988PTCO50073 =RAINBOW GARMENTS AND EXPORTS (INDIA) PRI
548 UU24230MH2004PTC147574 RAINBOW HERBAL AND RESEARCH PRIVATE LIMI
549 U55200MH1992PTCO067327 RAINBOW HOLIDAY-INNPVT.LTD.
 
550 U15100MH2004PTC148619 RAINBOW HORTICULTURE PRIVATE LIMITED
 
551 US9S99S9MH2000PTC124660 RAINBOW INFOTECH (INDIA) PRIVATE LIMITED
552 U70200MH2011PTC221779 RAINBOW INFRAVENTURES PRIVATE LIMITED
553 U15130MH2004P1C14/013 RAINBOW JELSTAR FOODS PRIVATE LIMITED
'''
 
print( re.findall(r'(?<!\S)(?=\S{19,21}(?!\S))U\S*\d{5}\S*\d(?!\S)',text) )

Output:

['U18101MH1988PTCO50073', 'U15100MH2004PTC148619', 'U70200MH2011PTC221779', 'U15130MH2004P1C14/013']

This regex works:

U.*\d{5}.*\d(?=\s)(?<=\S{19})(?<!\S{22})

We need to add the requirement for a space at the end of the match, and then ensure that there was at least 19 non-space characters before the match, and no more than 21.

Code for testing this:

values = re.findall('U.*\d{5}.*\d',text)
restrictedValues = [x for x in values if 21 >= len(x) >= 19]
print(values)
print ([len(x) for x in values ])

print(restrictedValues)
print ([len(x) for x in restrictedValues ])

restricted2 = re.findall('U.*\d{5}.*\d(?=\s)(?<=\S{19})(?<!\S{22})',text)
print(restricted2)
print([len(x) for x in restricted2])
Related