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


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.