9

Suppose there are two strings:

$1 off delicious ham.
$1 off delicious $5 ham.

In Python, can I have a regex that matches when there is only one $ in the string? I.e., I want the RE to match on the first phrase, but not on the second. I tried something like:

re.search(r"\$[0-9]+.*!(\$)","$1 off delicious $5 ham.")

..saying "Match where you see a $ followed by anything EXCEPT for another $." There was no match on the $$ example, but there was also no match on the $ example.

Thanks in advance!

Simple test method for checking:

def test(r):
  s = ("$1 off $5 delicious ham","$1 off any delicious ham")    
  for x in s:
    print x
    print re.search(r,x,re.I)
    print ""
Chris
  • 1,421
  • 3
  • 18
  • 31
  • 2
    why not use the `.count()` method of the strings? – John La Rooy Jul 02 '10 at 14:37
  • I'm shoe-horning an RE into a tool that doesn't let me add any additional logic. So I can't do "if count(str,"$") > 1: pass". I need the re to just not match on such a string. – Chris Jul 02 '10 at 14:52

5 Answers5

12
>>> import re
>>> onedollar = re.compile(r'^[^\$]*\$[^\$]*$')
>>> onedollar.match('$1 off delicious ham.')
<_sre.SRE_Match object at 0x7fe253c9c4a8>
>>> onedollar.match('$1 off delicious $5 ham.')
>>>

Breakdown of regexp:
^ Anchor at start of string
[^\$]* Zero or more characters that are not $
\$ Match a dollar sign
[^\$]* Zero or more characters that are not $
$ Anchor at end of string

MattH
  • 37,273
  • 11
  • 82
  • 84
7
>>> '$1 off delicious $5 ham.'.count('$')
2
>>> '$1 off delicious ham.'.count('$')
1
SilentGhost
  • 307,395
  • 66
  • 306
  • 293
2

You want to use the complement of a character class [^] to match any character other than $:

re.match(r"\$[0-9]+[^\$]*$","$1 off delicious $5 ham.")

The changes from your original are as follows:

  1. .* replaced with [^\$]*. The new term [^\$] means any character other than $
  2. $ appended to string. Forces the match to extend to the end of the string.
  3. re.search replaced with re.match. Matches the whole string, rather than any subset of it.
fmark
  • 57,259
  • 27
  • 100
  • 107
  • Didn't pass! >>> test(r"\$[0-9]+[^\$]*$") $1 off $5 delicious ham <_sre.SRE_Match object at 0x00ED65D0> $1 off any delicious ham <_sre.SRE_Match object at 0x00ED65D0> – Chris Jul 02 '10 at 14:56
1
re.search("^[^$]*\$[^$]*$",test_string)
John La Rooy
  • 295,403
  • 53
  • 369
  • 502
1
^.*?\$[^$]*$

this should make the trick

dweeves
  • 5,525
  • 22
  • 28
  • nice use of a non-greedy match – a'r Jul 02 '10 at 14:42
  • Hmm.. Didn't pass the test, though, unless there are some special flags I need:
        >>> test(r"^.*?\$[^$]*$")
        $1 off $5 delicious ham
        <_sre.SRE_Match object at 0x00ED6288>
        
        $1 off any delicious ham
        <_sre.SRE_Match object at 0x00ED6288>
        
    
    – Chris Jul 02 '10 at 14:51