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


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.