如何删除字符串的左侧部分?


144

我有一些简单的python代码,可在文件中搜索字符串,例如path=c:\path,其中c:\path部分可能会有所不同。当前代码是:

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=" ?

取得文字的简单方法是什么Path=


请注意,您正在以“ Path =“开头的文件中的第一行出现。此帖子的其他答案也可以。但是,如果该文件类似于DOS批处理文件,则您实际上可能希望此类文件的最后一行出现,这取决于“批处理”或命令文件中是否未填充条件。
DevPlayer

Answers:



196

如果字符串是固定的,则可以简单地使用:

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

它将为您提供字符串中从位置5开始的所有内容(字符串也是一个序列,因此这些序列运算符也可以在此处使用)。

或者,您可以先分割行=

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

然后,param是“ Path”,值是第一个=之后的其余值。


3
拆分方法+1,避免了在len(prefix)上手动切片时的轻微难看。
2009年

1
但是,如果您输入的内容不是“ something = somethingelse”的形式,也会抛出该错误。
丹·奥尔森,2009年

1
这就是为什么我将条件放在最前面的原因,因此仅在字符串中包含“ =”时才使用该条件。否则,您还可以测试split()结果的长度以及它是否== 2。
MrTopf

7
就像丹·奥尔森(Dan Olson)所说split,如果分隔符不存在,则会引发异常。partition更加稳定,它还会拆分一个字符串,并始终返回一个三元素元组,其中包含前内容,分隔符和后内容(其中某些内容可能''是不存在分隔符的情况)。例如value = line.partition('=')
Anders Johansson 2013年

1
如果不存在分隔符,则Split不会引发异常,它会返回包含整个字符串的列表。至少在python 2.7下
Maxim

122

从字符串中删除前缀

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

在第一次出现分隔符时通过 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

使用ConfigParser解析类似INI的文件

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

其他选择


1
缩进三个空格而不是四个空格的一种罕见原因。
鲍勃·斯坦

25
def remove_prefix(text, prefix):
    return text[len(prefix):] if text.startswith(prefix) else text

1
我喜欢这一点,因为您可以将“ else text”替换为“ else False”或“ else None”或要返回的任何-type-,以指示文件中的行不是以“ Path =“开头。我个人喜欢用括号将三元运算符括起来,以便在视觉上脱颖而出。
DevPlayer

19

一般来说,对于切片(有条件的或无条件的),我更喜欢同事最近提出的建议;使用带有空字符串的替换。更容易阅读代码,更少的代码(有时),以及减少指定错误字符数的风险。好; 我不使用Python,但在其他语言中,我更喜欢这种方法:

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

或-跟进该帖子的第一条评论--仅当行开头为时才应这样做Path

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

与上面建议的一些建议的主要区别在于,不涉及“幻数”(5),也不需要同时指定“ 5字符串“ Path=”,换句话说,我更喜欢代码维护中的这种方法。观点看法。


它不起作用:'c = Path = a'.replace(“ Path =”,“”,1)->'c = a'。
jfs

3
这不符合以“ Path =“开头的字符串的原始要求。
小狗

1
您可以将justex代码替换为just rightmost = re.sub('^Path=', '', fullPath)。该compile()方法的目的是在重用已编译的对象时使事情变得更快,但是由于在使用它后将其丢弃,因此无论如何它都没有效果。无论如何,通常不值得担心这种优化。
吉姆·奥尔菲尔德

13

我更喜欢pop索引[-1]

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

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

2
没有“幻数”的不错选择。值得一提的是,这是可行的,因为startswith已经过测试,因此split可以在之前和之后的所有内容之间进行除法。split("Path=", 1)更精确(如果前缀在字符串的后面再次出现),但是重新引入了幻数。
Quornian

1
简短版本(非常重要)的先前注释:仅当您首先使用startswith()测试时,此方法才有效。
MarcH 2013年

12

还是为什么不

if line.startswith(prefix):
    return line.replace(prefix, '', 1)

5

怎么样..

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

这个三元组是头部,分隔符和尾部


这并非在所有情况下都以相同的方式起作用。如果存在分隔符,则结果为第三项。否则,结果为第一项。
Ioannis Filippidis

5

我能想到的最简单的方法是切片:

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

快速了解切片符号,它使用两个索引而不是通常的索引。第一个索引指示要包含在切片中的序列的第一个元素,最后一个索引是要包含在切片中的最后一个元素之后的索引。
例如:

sequence_obj[first_index:last_index]

切片由所有的元素first_indexlast_index,包括first_index和不last_index。如果省略第一个索引,则默认为序列的开始。如果省略了最后一个索引,则它包括序列中最后一个元素之前的所有元素。也可以使用负索引。使用Google了解有关该主题的更多信息。


4
>>> import re

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

>>> path = "path=c:\path"

>>> re.match(p, path).group(1)
'c:\\path'

1.使用r''字符串作为Windows路径。2. re.match()可能返回None
jfs

3

在此未提及的另一个简单的单线:

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

这对于各种边缘情况也将正常工作:

>>> 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])
""



1

如果您知道列表理解:

lines = [line[5:] for line in file.readlines() if line[:5] == "Path="]

一项编辑建议line.startswith(...)速度提高10倍。我的测试没有证实这一点。如果提供支持断言的证据,则很乐意更改它。
马修·辛克尔

0

流行版本不太正确。我想你要:

>>> print('foofoobar'.split('foo', 1).pop())
foobar

0

为什么不使用带有转义符的正则表达式? ^匹配行的起始部分并re.MULTILINE在每行上匹配。re.escape确保匹配正确。

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

0

尝试以下代码

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

1
您的答案和接受的答案有什么区别?我看到这是另一个答案的第一部分。
eyllanesc

-1

我想这正是您要寻找的

    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

-1

无需编写函数,此操作将根据列表进行拆分,在这种情况下为'Mr. | Dr. | Mrs。',使用[1]进行拆分后选择所有内容,然后再次拆分并获取任何元素。在以下情况下,将返回“ Morris”。

re.split('Mr.|Dr.|Mrs.', 'Mr. Morgan Morris')[1].split()[1]

-1

这在技术上与其他答案非常相似,但是没有重复的字符串操作,能够分辨前缀是否存在,并且仍然可读性强:

parts = the_string.split(prefix_to_remove, 1):
    if len(parts) == 2:
        #  do things with parts[1]
        pass
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.