how can i correct this Regex phone number extractor in python
<p>The results i'm getting when i run this after copying a set of UK phone numbers to the clipboard are coming out in a very bizarre kind of way.
(i have imported both modules before you ask)</p>

<pre><code>phoneRegex = re.compile(r'''(
    (\d{5}|\(\d{5}\))?       #area code
    (\s|-|\.)?               #separator
    (\d{6})                  #main 6 digits
    )''', re.VERBOSE)

emailRegex = re.compile(r'''(
    [a-zA-Z0-9._%+-]+        #username
    @                        #obligatory @ symbol
    [a-zA-Z0-9.-]+           #domain name
    (\.[a-zA-Z]{2,5})        #dot-something
    )''', re.VERBOSE)

text = str(pyperclip.paste())

matches = []
for groups in phoneRegex.findall(text):
    phoneNum = '-'.join([groups[1], groups[3]])
    if groups[3] != '':
        phoneNum += ' ' + groups[3]
    matches.append(phoneNum)
for groups in emailRegex.findall(text):
    matches.append(groups[0])
if len(matches) &gt; 0:
    pyperclip.copy('\n'.join(matches))
    print('Copied to clipboard:')
    print('\n'.join(matches))
else:
    print('No phone numbers or email addresses found')
</code></pre>

<p>The mistake is somewhere here:</p>

<pre><code>for groups in phoneRegex.findall(text):
    phoneNum = '-'.join([groups[1], groups[3]])
    if groups[3] != '':
        phoneNum += ' ' + groups[3]
    matches.append(phoneNum)
</code></pre>

<p><strong>The numbers copied to clipboard:</strong> <br/>
07338 754433<br/>
01265768899<br/>
(01283)657899<br/></p>

<p><strong>Expected results:</strong><br/>
Copied to clipboard:<br/>
07338 754433<br/>
01265 768899<br/>
01283 657899<br/></p>

<p><strong>return results:</strong><br/>
Copied to clipboard:<br/>
07338-754433 754433<br/>
-012657 012657<br/>
(01283)-657899 657899</p>

<p>I see three issues:</p>

<ol>
<li><p>the python code joins the two parts of the phone number together with a <code>-</code> and then adds a space and the third part again:</p>

<pre><code>    phoneNum = '-'.join([groups[1], groups[3]])
    if groups[3] != '':
        phoneNum += ' ' + groups[3]
</code></pre>

<p>Since <code>groups[3]</code> will always not be blank, what you need to do is:</p>

<pre><code>    if groups[1] != '':
        phoneNum = ' '.join(groups[1], groups[3])
    else:
        phoneNum = groups[3]
</code></pre></li>
<li><p>Your <code>phoneRegex</code> regular expression is not anchored to the beginning and end of the lines.  You need to (a) compile it with the <code>re.MULTILINE</code> option and (b) anchor the regular expression between <code>^</code> and <code>$</code>:</p>

<pre><code>phoneRegex = re.compile(r'''^(
    (\d{5}|\(\d{5}\))?       #area code
    (\s|-|\.)?               #separator
    (\d{6})                  #main 6 digits
    )$''', re.VERBOSE + re.MULTILINE)
</code></pre>

<p>This will prevent a long string of digits with no separator as being just group 3 with a bunch of digits after it.</p></li>
<li><p>Your match for the area code includes the matched parentheses within the group match.  To fix this, you either need to change the regular expression to make sure the parentheses are not part of the group, or you need to change your code to strip the parentheses out if needed.</p>

<ul>
<li><p>Avoid parentheses in the regular expression:</p>

<pre><code>    (?:(\d{5})|\((\d{5})\))?       #area code
</code></pre>

<p>The <code>(?:...)</code> is a non-grouping form of parentheses, so it won't be returned by the find.  Within that, you have two alternatives:  5 digits in a group - <code>(\d{5})</code> - or literal parentheses that enclose 5 digits in a group - <code>\((\d{5})\)</code>.</p>

<p>However, this change also affects your phone number recombination logic, because your area code is <em>either</em> in <code>groups[1]</code> or <code>groups[2]</code>, and your main number is now in <code>groups[4]</code>.</p>

<pre><code>    if groups[1] != '':
        phoneNum = ' '.join(groups[1], groups[4])
    elif groups[2] != '':
        phoneNum = ' '.join(groups[2], groups[4])
    else:
        phoneNum = groups[4]
</code></pre>

<ul>
<li><p>This could be made easier by changing the outer set of parentheses and the parentheses around the separator into non-grouping parentheses.  You could then do a single join on a filtered result of the groups:</p>

<pre><code>phoneRegex = re.compile(r'''(?:
    (?:(\d{5})|\((\d{5})\))?       #area code
    (?:\s|-|\.)?               #separator
    (\d{6})                  #main 6 digits
    )''', re.VERBOSE)

# ...
    phoneNum = ' '.join([group for group in groups if group != ''])
</code></pre>

<p>The modified <code>phoneRegex</code> ensures that the returned <code>groups</code> contain only an optional area code in <code>groups[0]</code> or <code>groups[1]</code> followed by the main number in <code>groups[2]</code>, no extraneous matches returned.  The code then filters out any groups that are empty and returns the rest of the groups joined by a space.</p></li>
</ul></li>
<li><p>Strip parentheses in code:</p>

<pre><code>    if groups[1] != '':
        phoneNum = ' '.join(groups[1].lstrip('(').rstrip(')'), groups[3])
    else:
        phoneNum = groups[3]
</code></pre></li>
</ul></li>
</ol>

python regex