Как удалить левую часть строки?


146

У меня есть простой код 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

Ответы:


34

Начиная с Python 3.9, вы можете использовать removeprefix:

'Path=helloworld'.removeprefix('Path=')
# 'helloworld'

9
много путешествуете во времени? ;-) from PEP 596 - Python 3.9 Release Schedule : 3.9.0 final: Monday, 2020-10-05
ssc

2
Я собирался написать решение для python 3.9, но, похоже, вы везде упоминали решения для python 3.9. :)
Pygirl

199

Если строка исправлена, вы можете просто использовать:

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

который дает вам все, начиная с позиции 5 в строке (строка также является последовательностью, поэтому эти операторы последовательности работают и здесь).

Или вы можете сначала разделить строку =:

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

Тогда param - "Path", а значение - это остаток после первого =.


4
+1 для метода разделения, позволяет избежать небольшого уродства ручной нарезки на len (префикс).
bobince 01

1
Но также бросает, если ваш ввод не весь в форме «something = somethingelse».
Дэн Олсон

1
Вот почему я поставил условие впереди, чтобы оно использовалось, только если в строке стоит знак «=». В противном случае вы также можете проверить длину результата split () и равен ли он == 2.
MrTopf 01

8
Как говорит Дэн Олсон, splitвызывает исключение, если разделитель отсутствует. partitionболее стабилен, он также разбивает строку и всегда возвращает трехэлементный кортеж с пре-, разделителем и пост-содержимым (некоторые из которых могут быть, ''если разделитель отсутствовал). Например, value = line.partition('=').
Андерс Йоханссон

1
Split не генерирует исключение, если разделитель отсутствует, он возвращает список со всей строкой. Как минимум под python 2.7
Максим

127

Удалить префикс из строки

# ...
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

Анализируйте INI-подобный файл с помощью 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

Другие варианты


1
Одна редкая причина для отступа в три пробела вместо четырех.
Боб Стейн

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

1
Мне нравится этот, потому что вы можете заменить «else text» на «else False» или «else None» или любой другой тип -, который вы хотите вернуть, чтобы указать, что строка в файле не начинается с «Path =». Лично мне нравится окружать свои тернарные операторы круглыми скобками, чтобы выделяться визуально.
DevPlayer

20

Для нарезки (условной или безусловной) в целом я предпочитаю то, что недавно предложил коллега; Используйте замену пустой строкой. Легче читать код, меньше кода (иногда) и меньше риск указать неправильное количество символов. ОК; Я не использую 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 =».
Puppy

1
Вы можете заменить код регулярного выражения просто на 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
Более короткая версия (очень важного) предыдущего комментария: это работает ТОЛЬКО, если вы сначала протестируете с помощью startwith ().
MarcH


5

Как насчет..

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

Эта тройка - голова, разделитель и хвост .


Не во всех случаях это работает одинаково. Если разделитель присутствует, то результат - третий элемент. В противном случае результат будет первым.
Иоаннис Филиппидис

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_indexи last_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])
""


2

Если вы знаете состав списка:

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

Была редакция, предполагающая, что line.startswith(...)это в 10 раз быстрее. Мои испытания этого не подтвердили. Рад изменить его, если будут представлены доказательства, подтверждающие это утверждение.
Мэтью Шинкель

1

Почему бы не использовать регулярное выражение с escape? ^соответствует начальной части строки и re.MULTILINEсоответствует каждой строке. re.escapeгарантирует точное соответствие.

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

1

Попробуйте следующий код

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

1
В чем разница между вашим ответом и принятым ответом? Я вижу, что это первая часть другого ответа.
eyllanesc

1

removeprefix()и removesuffix() методы струнных , добавленные в Python 3.9 из - за проблемы , связанные с lstripи rstripинтерпретацией параметров , передаваемых им. Прочтите PEP 616 для более подробной информации.

# 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 пример со списком:

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

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

выход:

car
phone
star
book

removeprefix пример со списком:

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

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

выход:

['York', 'Zealand', 'Delhi', 'Now']

0

Поп-версия была не совсем подходящей. Я думаю, вы хотите:

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

-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], затем снова разделите и возьмите любой элемент. В приведенном ниже случае возвращается «Моррис».

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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.