173

I have some simple python code that searches files for a string e.g. path=c:\path, where the c:\path part may vary. The current code is:

def find_path(i_file):
    lines = open(i_file).readlines()
    for line in lines:
        if line.startswith("Path="):
            return # what to do here in order to get line content after "Path=" ?

What is a simple way to get the text after Path=?

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
grigoryvp
  • 40,413
  • 64
  • 174
  • 277
  • Be aware that you are returning on the first line occurrence within the file that starts with "Path=". Other answers to this post also do. But if the file is something like a DOS batch file you may actually want the last line occurrence from such a file depending if the "batch" or command file isn't filled with conditionals. – DevPlayer Aug 27 '16 at 23:29

21 Answers21

210

If the string is fixed you can simply use:

if line.startswith("Path="):
    return line[5:]

which gives you everything from position 5 on in the string (a string is also a sequence so these sequence operators work here, too).

Or you can split the line at the first =:

if "=" in line:
    param, value = line.split("=",1)

Then param is "Path" and value is the rest after the first =.

John Zwinck
  • 239,568
  • 38
  • 324
  • 436
MrTopf
  • 4,813
  • 2
  • 24
  • 19
  • 5
    +1 for the split method, avoids the slight ugliness of the manual slicing on len(prefix). – bobince Mar 01 '09 at 16:38
  • 1
    But also throws if your input isn't all in the form "something=somethingelse". – Dan Olson Mar 01 '09 at 22:17
  • 1
    That's why I put the condition in front so it's only used if a "=" is in the string. Otherwise you can also test for the length of the result of split() and if it's ==2. – MrTopf Mar 01 '09 at 22:33
  • 8
    Like Dan Olson says `split` throws an exception if the delimiter is not present. `partition` is more stable, it also splits a string and *always* returns a three-element tuple with pre-, delimiter, and post-content (some of which may be `''` if the delimiter was not present). Eg, `value = line.partition('=')`. – Anders Johansson Jan 03 '13 at 14:21
  • 1
    Split doesn't throw an exception if the delimited is not present, it returns a list with the whole string. At least under python 2.7 – Maxim Aug 10 '17 at 11:30
  • It always feels a little unpythonic, but to avoid the unpacking exception when the delimiter is missing, I tend to use this a lot, value = line.split("=",1)[-1]. The line will always split once on "=" if it's present, and will return the whole line otherwise. This is a compliment to: pre, seperator, value = line.partition("="), depending on if I want the sting if it's missing the separator or not. – milesvp May 17 '18 at 22:35
  • @Maxim: The exception is from unpacking to two names; if the `split` doesn't split into two parts, the unpack throws the exception. `param, sep, value = line.partition("=")` never does, because `str.partition` always returns a three-`tuple` (when the partition character isn't there, `sep` and `value` would be the empty string). – ShadowRanger Jan 07 '20 at 22:00
136

Remove prefix from a string

# ...
if line.startswith(prefix):
   return line[len(prefix):]

Split on the first occurrence of the separator via str.partition()

def findvar(filename, varname="Path", sep="=") :
    for line in open(filename):
        if line.startswith(varname + sep):
           head, sep_, tail = line.partition(sep) # instead of `str.split()`
           assert head == varname
           assert sep_ == sep
           return tail

Parse INI-like file with ConfigParser

from ConfigParser import SafeConfigParser
config = SafeConfigParser()
config.read(filename) # requires section headers to be present

path = config.get(section, 'path', raw=1) # case-insensitive, no interpolation

Other options

Community
  • 1
  • 1
jfs
  • 399,953
  • 195
  • 994
  • 1,670
96

Starting in Python 3.9, you can use removeprefix:

'Path=helloworld'.removeprefix('Path=')
# 'helloworld'
Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
44

Python 3.9+

text.removeprefix(prefix)

Any Python version:

def remove_prefix(text, prefix):
    return text[len(prefix):] if text.startswith(prefix) else text
David Foster
  • 6,931
  • 4
  • 41
  • 42
  • 1
    I like this one because you can replace "else text" with "else False" or "else None" or whatever -type- you want to return to indicate that the line in the file did not start with "Path=". Personally I like to surround my ternary operators with parentheses to stand out visually. – DevPlayer Aug 27 '16 at 23:02
  • Useful one-liner: `remove_prefix = lambda text, prefix: text[len(prefix):] if text.startswith(prefix) else text` – Basj Apr 29 '22 at 16:49
21

For slicing (conditional or non-conditional) in general I prefer what a colleague suggested recently; Use replacement with an empty string. Easier to read the code, less code (sometimes) and less risk of specifying the wrong number of characters. Ok; I do not use Python, but in other languages I do prefer this approach:

rightmost = full_path.replace('Path=', '', 1)

or - to follow up to the first comment to this post - if this should only be done if the line starts with Path:

rightmost = re.compile('^Path=').sub('', full_path)

The main difference to some of what has been suggested above is that there is no "magic number" (5) involved, nor any need to specify both '5' and the string 'Path=', In other words I prefer this approach from a code maintenance point of view.

0 _
  • 10,524
  • 11
  • 77
  • 109
fredarin
  • 784
  • 5
  • 14
  • It doesn't work: 'c=Path=a'.replace("Path=", "", 1) -> 'c=a'. – jfs Mar 01 '09 at 17:55
  • 3
    That does not meet the original requirement of the string starting with "Path=". – Puppy Jan 21 '15 at 17:25
  • 2
    You can replace the regex code with just `rightmost = re.sub('^Path=', '', fullPath)`. The purpose of the `compile()` method is to make things faster if you reuse the compiled object, but since you throw it away after you use it, it has no effect here anyway. It's usually not worth worrying about this optimisation anyway. – Jim Oldfield Aug 23 '16 at 08:50
  • I would add [`re.escape`](https://docs.python.org/3/library/re.html#re.escape) do the mix in case the prefix contains special characters. i.e. `re.compile('^' + re.escape('Path='))` – Cristian Ciupitu Jul 20 '21 at 19:49
15

I prefer pop to indexing [-1]:

value = line.split("Path=", 1).pop()

to

value = line.split("Path=", 1)[1]
param, value = line.split("Path=", 1)
Asclepius
  • 57,944
  • 17
  • 167
  • 143
Thomas Schreiber
  • 1,828
  • 2
  • 14
  • 11
  • 2
    Nice alternative without "magic numbers". It's worth noting that this works because `startswith` has already been tested so `split` will divide "nothing" before and everything else after. `split("Path=", 1)` is more precise (in case of the prefix reappearing later in the string) but reintroduces a magic number. – quornian May 23 '13 at 21:25
  • 1
    Shorter version of the (very important) previous comment: this works ONLY if you test with startswith() first. – MarcH Jun 13 '13 at 13:38
12

Or why not

if line.startswith(prefix):
    return line.replace(prefix, '', 1)
John Damen
  • 399
  • 4
  • 8
6

The simplest way I can think of is with slicing:

def find_path(i_file): 
    lines = open(i_file).readlines() 
    for line in lines: 
        if line.startswith("Path=") : 
            return line[5:]

A quick note on slice notation, it uses two indices instead of the usual one. The first index indicates the first element of the sequence you want to include in the slice and the last index is the index immediately after the last element you wish to include in the slice.
Eg:

sequence_obj[first_index:last_index]

The slice consists of all the elements between first_index and last_index, including first_index and not last_index. If the first index is omitted, it defaults to the start of the sequence. If the last index is omitted, it includes all elements up to the last element in the sequence. Negative indices are also allowed. Use Google to learn more about the topic.

Boris Verkhovskiy
  • 14,854
  • 11
  • 100
  • 103
batbrat
  • 5,155
  • 3
  • 32
  • 38
5

How about..

line = r'path=c:\path'
line.partition('path=')

Output:

('', 'path=', 'c:\\path')

This triplet is the head, separator, and tail.

Floggedhorse
  • 694
  • 8
  • 15
  • 2
    This doesn't work in all cases the same way. If the separator is present, then the result is the third item. Otherwise, the result is the first item. – 0 _ Sep 20 '17 at 05:53
  • You also have the third case where the separator is in the middle: `"manpath=c:\path"` – Troy Daniels Feb 06 '23 at 21:17
5

Another simple one-liner that hasn't been mentioned here:

value = line.split("Path=", 1)[-1]

This will also work properly for various edge cases:

>>> print("prefixfoobar".split("foo", 1)[-1])
"bar"

>>> print("foofoobar".split("foo", 1)[-1])
"foobar"

>>> print("foobar".split("foo", 1)[-1])
"bar"

>>> print("bar".split("foo", 1)[-1])
"bar"

>>> print("".split("foo", 1)[-1])
""
pR0Ps
  • 2,752
  • 2
  • 23
  • 26
4
import re

p = re.compile(r'path=(.*)', re.IGNORECASE)

path = r"path=c:\path"

re.match(p, path).group(1)

Output:

'c:\\path'
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
riza
  • 16,274
  • 7
  • 29
  • 29
4

removeprefix() and removesuffix() string methods added in Python 3.9 due to issues associated with lstrip and rstrip interpretation of parameters passed to them. Read PEP 616 for more details.

# in python 3.9
>>> s = 'python_390a6'

# apply removeprefix()
>>> s.removeprefix('python_')
'390a6'

# apply removesuffix()
>>> s = 'python.exe'
>>> s.removesuffix('.exe')
'python'

# in python 3.8 or before
>>> s = 'python_390a6'
>>> s.lstrip('python_')
'390a6'

>>> s = 'python.exe'
>>> s.rstrip('.exe')
'python'

removesuffix example with a list:

plurals = ['cars', 'phones', 'stars', 'books']
suffix = 's'

for plural in plurals:
    print(plural.removesuffix(suffix))

output:

car
phone
star
book

removeprefix example with a list:

places = ['New York', 'New Zealand', 'New Delhi', 'New Now']

shortened = [place.removeprefix('New ') for place in places]
print(shortened)

output:

['York', 'Zealand', 'Delhi', 'Now']
Milovan Tomašević
  • 6,823
  • 1
  • 50
  • 42
3
line[5:]

gives you characters after the first five.

Steven Huwig
  • 20,015
  • 9
  • 55
  • 79
2

Why not using regex with escape? ^ matches the initial part of a line and re.MULTILINE matches on each line. re.escape ensures that the matching is exact.

>>> print(re.sub('^' + re.escape('path='), repl='', string='path=c:\path\nd:\path2', flags=re.MULTILINE))
c:\path
d:\path2
2

line[5:] will give the substring you want. Search the introduction and look for 'slice notation'

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
1

If you know list comprehensions:

lines = [line[5:] for line in file.readlines() if line[:5] == "Path="]
Matthew Schinckel
  • 35,041
  • 6
  • 86
  • 121
  • There was an edit suggesting `line.startswith(...)` is 10X faster. My testing did not confirm this. Happy to change it if evidence supporting that assertion is provided. – Matthew Schinckel Oct 09 '14 at 03:32
0

Try Following code

if line.startswith("Path="): return line[5:]
dipenparmar12
  • 3,042
  • 1
  • 29
  • 39
  • 2
    What is the difference between your answer and the answer accepted? I see that it is in the first part of the other answer. – eyllanesc Jun 12 '19 at 15:08
-1

I guess this what you are exactly looking for

    def findPath(i_file) :
        lines = open( i_file ).readlines()
        for line in lines :
            if line.startswith( "Path=" ):
                output_line=line[(line.find("Path=")+len("Path=")):]
                return output_line
Pramod Bhat
  • 568
  • 4
  • 9
-2

without having a to write a function, this will split according to list, in this case 'Mr.|Dr.|Mrs.', select everything after split with [1], then split again and grab whatever element. In the case below, 'Morris' is returned.

re.split('Mr.|Dr.|Mrs.', 'Mr. Morgan Morris')[1].split()[1]
xristian
  • 51
  • 8
-2

The below method can be tried.

def remove_suffix(string1, suffix):
    length = len(suffix)

    if string1[0:length] == suffix:
        return string1[length:]
    else:
        return string1

suffix = "hello"
string1 = "hello world"

final_string = remove_suffix(string1, suffix)
print (final_string)
SuperNova
  • 25,512
  • 7
  • 93
  • 64
-3

This is very similar in technique to other answers, but with no repeated string operations, ability to tell if the prefix was there or not, and still quite readable:

parts = the_string.split(prefix_to_remove, 1):
    if len(parts) == 2:
        #  do things with parts[1]
        pass
Kiwi
  • 7
  • 1
  • 4