In python, test for 1 or 3 consecutive instances of a string, but not 2 (without regex)

StackOverflow https://stackoverflow.com/questions/19498771

  •  01-07-2022
  •  | 
  •  

Domanda

I am dealing with data in which...

* marks property A
** marks property B
*** marks properties A & B

text1 = "spam*eggs"   # A
text2 = "eggs**spam"  # B
text3 = "spam***spam" # A & B

Testing for property B is easy,

"**" in <string>

but testing for property A with the same strategy would give a false positive with text2.

>>> "*" in text2
True

I want to test for property A. Is there a pythonic way to do this without using regular expressions? I don't want to use regex because I share code with beginner programmers who are not familiar with it.

È stato utile?

Soluzione 5

It is not clear if you want to just test for Property A, as in the text, or A or C, as in the title. (C being A and B)

To just get True or False for 1 or 3 and not 2, you can use a code rephrasing of your logic:

result = '***' in x or (not  '**' in x and '*' in x)

To get the letter of ABC out depending on the pattern:

result = ['None','A','B','C'][('*' in x) + ('**' in x) + ('***' in x)]

To just test for Property A (one star) without failing on two or three. (EDIT: simplified this. If ** is not there then neither is ***):

isItA = '*' in x and not  '**' in x

Altri suggerimenti

Try this:

idx = txt.index('*')
if txt[idx+1] != '*':
    print 'A'
elif txt[idx+2] != '*':
    print 'B'
else:
    print 'A & B'

The above will raise exceptions for the corner cases - for example, if the string is not present, or if the string is the last character. This solution has the added benefit of performing a single traversal of the text (the call to index()).

Without Regex, you could do something like this:

if "***" in mystr:
    print "Property A & B"
elif "**" in mystr:
    print "Property B"
elif "*" in mystr:
    print "Property A"

You can count the occurrences of '*':

>>> text1.count('*')
1
>>> text2.count('*')
2
>>> text3.count('*')
3

So your check would be text.count('*') in (1, 3)

That said, I agree with the commenter - regular expressions are right for this kind of problem.

>>> properties = {1: 'A', 2: 'B', 3: 'A & B'}
>>> import re
>>> text = 'eggs***spam'
>>> match = re.search(r'\*+', text)
>>> if match:
...    print properties[len(match.group(0))]
... else:
...    print 'None'
A & B

Well, I wouldn't say it's Pythonic, but you could group them and make sure the consecutive occurrences are of a certain length - either 1 or 3 to exclude ** for instance, eg:

from itertools import groupby
print any(k=='*' and len(list(g)) in (1, 3) for k, g in groupby(s))
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top