简体   繁体   中英

regex matching with multiple conditions

I need to obtain a string of letters from the following rows_string variable:

'Equity & 1,638 & \\$3,227,305 & \\$2,649,208 & \\$3,270,402 & \\$3,114,298 & \\$3,173,369 & \\$2,978,769 & \\$3,016,161 & \\$2,807,840\\\\\nFixed Income & 420 & \\$765,856 & \\$661,395 & \\$824,603 & \\$792,579 & \\$794,224 & \\$783,793 & \\$719,307 & \\$630,298\\\\\nCommodities & 119 & \\$72,911 & \\$66,302 & \\$81,649 & \\$81,633 & \\$79,296 & \\$76,450 & \\$64,136 & \\$63,667\\\\\nAsset Allocation & 63 & \\$10,190 & \\$9,275 & \\$10,684 & \\$10,089 & \\$10,371 & \\$9,829 & \\$9,619 & \\$8,880\\\\\nAlternatives & 55 & \\$5,601 & \\$6,023 & \\$6,715 & \\$6,279 & \\$6,365 & \\$6,645 & \\$6,757 & \\$6,243\\\\\nCurrency & 34 & \\$311 & \\$2,014 & \\$1,665 & \\$1,743 & \\$1,683 & \\$1,666 & \\$1,722 & \\$2,058\\\\\nTOTALS & 2,329 & \\$4,082,173 & \\$3,394,217 & \\$4,195,718 & \\$4,006,620 & \\$4,065,308 & \\$3,857,151 & \\$3,817,700 & \\$3,518,986\\\\'

So for instance, I need the following list:

[Equity, Fixed Income, Commodities, Asset Allocation, Alternatives, Currency, Total]

I tried:

re.findall(r'\\\\\n(\w+.*?) &', rows_string)

Great but this omits the "equity" variable And also gives me an empty list for this string variable

'Starting Portfolio & sell & 21.39\\% & -0.91\\% & 1.52\\% & 9.29\\% & 9.72\\% & 14.89\\% & 38.21\\% & 55.4\\% &  & 90.86\\%\\\\'

So for the second string, I need ['Starting Portfolio', 'sell'] What I want is to grab the first item following \\\\\\\\\\n and first item before the '&' in the string variable. Thank you

You are just missing one \\ . You are not searching for the letters \\ and n but instead for a line break. So just ad \\ at the beginning of your regex. Also you are missing the first entry since you state, that your word starts with \\\\\\\\\\n . To also get the first you could use ^(\\w+.*?)|[\\\\\\\\\\n](\\w+.*?) & for example

I don't think there's any reason to focus on the escaped newlines. This should do the trick:

import re

pattern = r'\b[A-Za-z ]*[A-Za-z]\b'

rows_string = 'Equity & 1,638 & \\$3,227,305 & \\$2,649,208 & \\$3,270,402 & \\$3,114,298 & \\$3,173,369 & \\$2,978,769 & \\$3,016,161 & \\$2,807,840\\\\\nFixed Income & 420 & \\$765,856 & \\$661,395 & \\$824,603 & \\$792,579 & \\$794,224 & \\$783,793 & \\$719,307 & \\$630,298\\\\\nCommodities & 119 & \\$72,911 & \\$66,302 & \\$81,649 & \\$81,633 & \\$79,296 & \\$76,450 & \\$64,136 & \\$63,667\\\\\nAsset Allocation & 63 & \\$10,190 & \\$9,275 & \\$10,684 & \\$10,089 & \\$10,371 & \\$9,829 & \\$9,619 & \\$8,880\\\\\nAlternatives & 55 & \\$5,601 & \\$6,023 & \\$6,715 & \\$6,279 & \\$6,365 & \\$6,645 & \\$6,757 & \\$6,243\\\\\nCurrency & 34 & \\$311 & \\$2,014 & \\$1,665 & \\$1,743 & \\$1,683 & \\$1,666 & \\$1,722 & \\$2,058\\\\\nTOTALS & 2,329 & \\$4,082,173 & \\$3,394,217 & \\$4,195,718 & \\$4,006,620 & \\$4,065,308 & \\$3,857,151 & \\$3,817,700 & \\$3,518,986\\\\'

rows = re.findall(pattern, rows_string)

print(rows)

rows_string2 = 'Starting Portfolio & sell & 21.39\\% & -0.91\\% & 1.52\\% & 9.29\\% & 9.72\\% & 14.89\\% & 38.21\\% & 55.4\\% &  & 90.86\\%\\\\'

rows2 = re.findall(pattern, rows_string2)

print(rows2)

Try this pattern with re.finditer() :

pattern = r"(((?!\\\\\\\\\\n)([a-zA-Z\\s]+))|([a-zA-Z\\s]{2,}\\s?(?!\\&)))"
output_list = [i.group().strip() for i in re.finditer(pattern, rows_string) if i.group().strip()]

Inputs :

s1 = 'Equity & 1,638 & \\$3,227,305 & \\$2,649,208 & \\$3,270,402 & \\$3,114,298 & \\$3,173,369 & \\$2,978,769 & \\$3,016,161 & \\$2,807,840\\\\\nFixed Income & 420 & \\$765,856 & \\$661,395 & \\$824,603 & \\$792,579 & \\$794,224 & \\$783,793 & \\$719,307 & \\$630,298\\\\\nCommodities & 119 & \\$72,911 & \\$66,302 & \\$81,649 & \\$81,633 & \\$79,296 & \\$76,450 & \\$64,136 & \\$63,667\\\\\nAsset Allocation & 63 & \\$10,190 & \\$9,275 & \\$10,684 & \\$10,089 & \\$10,371 & \\$9,829 & \\$9,619 & \\$8,880\\\\\nAlternatives & 55 & \\$5,601 & \\$6,023 & \\$6,715 & \\$6,279 & \\$6,365 & \\$6,645 & \\$6,757 & \\$6,243\\\\\nCurrency & 34 & \\$311 & \\$2,014 & \\$1,665 & \\$1,743 & \\$1,683 & \\$1,666 & \\$1,722 & \\$2,058\\\\\nTOTALS & 2,329 & \\$4,082,173 & \\$3,394,217 & \\$4,195,718 & \\$4,006,620 & \\$4,065,308 & \\$3,857,151 & \\$3,817,700 & \\$3,518,986\\\\'
s2 = 'Starting Portfolio & sell & 21.39\\% & -0.91\\% & 1.52\\% & 9.29\\% & 9.72\\% & 14.89\\% & 38.21\\% & 55.4\\% &  & 90.86\\%\\\\'*

Output :

['Equity', 'Fixed Income', 'Commodities', 'Asset Allocation', 'Alternatives', 'Currency', 'TOTALS']
['Starting Portfolio', 'sell']

To get the values, you might use an alternation to either match the words from the start of the string or get the words before &

(?:^[A-Za-z]+(?: [A-Za-z]+)*|[A-Za-z]+(?: [A-Za-z]+)*(?= &))
  • (?: Non capturing group
    • ^ Start of the line
    • [A-Za-z]+(?: [A-Za-z]+)* Match 1+ words with only chars A-Za-z
    • | Or
    • [A-Za-z]+(?: [A-Za-z]+)*(?= &) Match words followed by &
  • ) Close group

Regex demo | Python demo

For example

import re

pattern = r'(?:^[A-Za-z]+(?: [A-Za-z]+)*|[A-Za-z]+(?: [A-Za-z]+)*(?= &))'
rows_string = 'Equity & 1,638 & \\$3,227,305 & \\$2,649,208 & \\$3,270,402 & \\$3,114,298 & \\$3,173,369 & \\$2,978,769 & \\$3,016,161 & \\$2,807,840\\\\\nFixed Income & 420 & \\$765,856 & \\$661,395 & \\$824,603 & \\$792,579 & \\$794,224 & \\$783,793 & \\$719,307 & \\$630,298\\\\\nCommodities & 119 & \\$72,911 & \\$66,302 & \\$81,649 & \\$81,633 & \\$79,296 & \\$76,450 & \\$64,136 & \\$63,667\\\\\nAsset Allocation & 63 & \\$10,190 & \\$9,275 & \\$10,684 & \\$10,089 & \\$10,371 & \\$9,829 & \\$9,619 & \\$8,880\\\\\nAlternatives & 55 & \\$5,601 & \\$6,023 & \\$6,715 & \\$6,279 & \\$6,365 & \\$6,645 & \\$6,757 & \\$6,243\\\\\nCurrency & 34 & \\$311 & \\$2,014 & \\$1,665 & \\$1,743 & \\$1,683 & \\$1,666 & \\$1,722 & \\$2,058\\\\\nTOTALS & 2,329 & \\$4,082,173 & \\$3,394,217 & \\$4,195,718 & \\$4,006,620 & \\$4,065,308 & \\$3,857,151 & \\$3,817,700 & \\$3,518,986\\\\'
print(re.findall(pattern, rows_string, re.M))


rows_string2 = 'Starting Portfolio & sell & 21.39\\% & -0.91\\% & 1.52\\% & 9.29\\% & 9.72\\% & 14.89\\% & 38.21\\% & 55.4\\% &  & 90.86\\%\\\\'
print(re.findall(pattern, rows_string2, re.M))

Output

['Equity', 'Fixed Income', 'Commodities', 'Asset Allocation', 'Alternatives', 'Currency', 'TOTALS']
['Starting Portfolio', 'sell']

If all matches should be followed by & you might simplify the pattern to

[A-Za-z]+(?: [A-Za-z]+)*(?= &)

Regex demo

Assuming your target string (financial keyword) comes after a newline (or start of string) and before & you could do:

>>> re.findall(r'(?:\n|^)([A-Za-z ]+)\s&', s)
['Equity', 'Fixed Income', 'Commodities', 'Asset Allocation', 'Alternatives', 'Currency', 'TOTALS']

This uses some shortcuts, but depending on if you have more complex strings, such as "P&E", "Misc. Expenses", and such, the above might suffice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM