Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I am trying to replace a given pattern with regular expressions in Python, using re. Here is the piece of Python code I wrote:

import re

fname = './prec.f90'
f = open(fname)
lines = f.readlines()
f.close()
for i, line in enumerate(lines):
    search = re.findall('([\d*]?\.[\d*]?)+?[^dq\_]', line)
    if search != []: 
        print('Real found in line #%d: ' %i)
        print search
        print('The following line:\n %s' %line)
        print('will be replace by:')
        newline = re.sub('([\d*]?\.[\d*]?)+?[^dq\_]', r'\g<1>d0\g<2>', line)
        print('%s' %newline)

And the prec.f90 contains something like that (it is just an example, it does not means that all the strings I want to replace have the form [x]_[yz] = ...;):

  x_pr = 0.1; y_pr = 0.2; z_pr = 0.1q0
  x_sp = 0.1; y_sp = 0.1d0; z_sp = 0.1q0
  x_dp = 0.1; y_dp = 0.1d0; z_dp = 0.1q0
  x_qp = .1; y_qp = 0.1d0; z_qp = 0.1q0
  x_db = 0.; y_db = 0.1d0; y_db = 0.1q0

My goal is to modify all the pattern like 0.1, .1 and 0., to get something like 0.1d0; I don't want to modify the other patterns. The problem is that re.findall('[\d*]?\.[\d*]?)+?([^dq\_]') matches the pattern I am looking for, but also returns an empty string for the other ones. Therefore, when I run this piece of code, it fails, being unable to replace match the first and second groups in the re.sub() for the empty strings.

I guess one solution would be to ignore empty string in the re.sub, or to have something like a conditional argument in it, but I could not figure out how.

Any help would be appreciated!

share|improve this question
    
It is failing [subbing the empty string] because you made all the components optional with *. What is the minimum string that will be on a line that you want to replace? If it is .x then change the second \d* to \d+ –  beroe Nov 21 '14 at 18:58
    
Problem is they can have the 3 forms I mentioned: x.y, .y and x.. I want (and need) to cover all these cases. –  MBR Nov 23 '14 at 10:47

3 Answers 3

up vote 0 down vote accepted

I finally came up with this piece of code that is working as intended:

import re

fname = './prec.f90'
f = open(fname)
lines = f.readlines()
f.close()
# If there was no end of the line character (\n) we would need to check if 
# this is the end of the line (something like ([^dq\_0-9]|$)
regex = re.compile(r'(\d*\.\d*)([^dq\_0-9])')
for i, line in enumerate(lines):
    search = regex.findall(line)
    if search != []: 
        print('Real found in line #%d: ' %i)
        print search
        print('The following line:\n %s' %line)
        print('will be replace by:')
        newline = regex.sub(r'\g<1>d0\g<2>', line)
        print('%s' %newline)

I first came up with the more complicated regex ([\d*]?\.[\d*]?)+?[^dq\_] because else I always match the first part of any string ending with d, q or _. It seemed to be due to the fact that \d* was not greedy enough; to add 0-9 in the "ignore" set solves the problem.

share|improve this answer

You can simplify the sub as

>>> str="x_db = 0.; y_db = 0.1d0; y_db = 0.1q"
>>> re.sub(r'(0\.1|\.1|0\.)(?=;)', r'\g<1>0d0', str)
'x_db = 0.0d0; y_db = 0.1d0; y_db = 0.1q'

The regex (0\.1|\.1|0\.)(?=;) would match 0.1, .1 and 0. followed by as ;

share|improve this answer
    
Please read my edit, the strings I want to replace have a more general form, this was just an example. –  MBR Nov 21 '14 at 18:38
(x_[a-zA-Z]{2}\s*=)\s+[^;]+

Try this.Replace by \1 0.1d0.See demo.

http://regex101.com/r/qZ6sE3/2

import re
p = re.compile(ur'(x_[a-zA-Z]{2}\s*=)\s+[^;]+')
test_str = u"x_pr = 0.1; y_pr = 0.2; z_pr = 0.1q0\nx_sp = 0.1; y_sp = 0.1d0; z_sp = 0.1q0\nx_dp = 0.1; y_dp = 0.1d0; z_dp = 0.1q0\nx_qp = .1; y_qp = 0.1d0; z_qp = 0.1q0\nx_db = 0.; y_db = 0.1d0; y_db = 0.1q0"
subst = u"\1 0.1d0"

result = re.sub(p, subst, test_str)
share|improve this answer
    
The string I want to replace can have a much general form than x_[a-Z] = .... The test in my question is what it is: a simple test :) –  MBR Nov 23 '14 at 10:48
    
@MBR regex101.com/r/yP3iB0/6 ??????/ –  vks Nov 23 '14 at 12:08
    
nope, because I don't want to modify only the "0.1" but actualy any real number, and I don't have all my expressions ending with a semi-column. and I want to replace the original string by its value, not a dummy 0.1. –  MBR Nov 23 '14 at 17:06

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.