Як видалити ліву частину рядка?


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


Пам’ятайте, що ви повертаєтесь до появи першого рядка у файлі, який починається з «Шлях =». Інші відповіді на цю посаду також є. Але якщо файл чимось схожий на пакетний файл DOS, ви, можливо, хочете останнього появи рядка з такого файлу залежно від того, якщо "пакетний" або командний файл не заповнений умовними умовами.
— DevPlayer

Відповіді:


23

Починаючи з Python 3.9, ви можете використовувати removeprefix:

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

5
багато подорожуючи часом? ;-) від PEP 596 - Python 3.9 Графік випуску : 3.9.0 фінал: понеділок, 2020-10-05
— ssc

Я збирався написати рішення для python 3.9, але, здається, ви згадали рішення python 3.9 скрізь. :)
— Пігірл

196

Якщо рядок виправлено, ви можете просто скористатися:

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

яка дає вам все, починаючи з позиції 5 у рядку (рядок також є послідовністю, тому ці оператори послідовності також працюють тут).

Або ви можете розділити рядок спочатку =:

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

Тоді параметр - "Шлях", а значення - решта після першого =.


3
+1 для методу розколу, дозволяє уникнути незначної потворності ручного нарізання на len (приставка).
— bobince

1
Але також кидає, якщо ваш вклад не все у формі "щось = щось".
— Ден Олсон

1
Ось чому я поставив умову попереду, тому вона використовується лише в тому випадку, якщо в рядку є "=". В іншому випадку ви також можете перевірити тривалість результату split () і якщо він == 2.
— MrTopf

7
Як каже Ден Олсон, splitвикидає виняток, якщо роздільника немає. partitionє більш стабільним, він також розбиває рядок і завжди повертає триелементний кортеж з попереднім, роздільником та пост-вмістом (деякі з яких можуть бути, ''якщо роздільника не було). Наприклад, value = line.partition('=').
— Андерс Йоханссон

1
Спліт не кидає виняток, якщо обмеженого немає, він повертає список з усією рядком. Принаймні під пітоном 2.7
— Максим

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

Проаналізуйте 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
Одна рідкісна причина відступити три пробіли замість чотирьох.
— Боб Штейн

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 ("Шлях =", "", 1) ->' c = a '.
— jfs

3
Це не відповідає початковій вимозі рядка, що починається з "Шлях =".
— Щеня

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)є більш точним (у випадку, коли префікс з’явиться пізніше в рядку), але знову вводить магічне число.
— курінь

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



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

без того, щоб писати функцію, це розділиться відповідно до списку, у цьому випадку "Містер | Доктор. У нижченаведеному випадку "Морріс" повертається.

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.