Làm thế nào để loại bỏ phần bên trái của một chuỗi?


144

Tôi có một số mã python đơn giản để tìm kiếm các tệp cho một chuỗi path=c:\path, ví dụ , trong đó c:\pathphần có thể thay đổi. Mã hiện tại là:

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

Một cách đơn giản để có được văn bản sau là Path=gì?


Xin lưu ý rằng bạn đang quay lại lần xuất hiện đầu tiên trong tệp bắt đầu bằng "Path =". Câu trả lời khác cho bài này cũng làm. Nhưng nếu tệp giống như tệp bó DOS, bạn thực sự có thể muốn xuất hiện dòng cuối cùng từ tệp đó tùy thuộc vào việc "bó" hoặc tệp lệnh không chứa đầy các điều kiện.
DevPlayer 27/8/2016

Câu trả lời:


21

Bắt đầu từ Python 3.9, bạn có thể sử dụng removeprefix:

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

4
du hành thời gian nhiều? ;-) từ PEP 596 - Lịch phát hành Python 3.9 : Chung kết 3.9.0: Thứ Hai, 2020-10-05
ssc

Tôi sẽ viết giải pháp cho python 3.9 nhưng có vẻ như bạn đã đề cập đến các giải pháp python 3.9 ở khắp mọi nơi. :)
Pygirl

196

Nếu chuỗi được cố định, bạn chỉ cần sử dụng:

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

cung cấp cho bạn mọi thứ từ vị trí 5 trên chuỗi (chuỗi cũng là một chuỗi để các toán tử trình tự này cũng hoạt động ở đây).

Hoặc bạn có thể chia dòng đầu tiên =:

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

Sau đó, param là "Đường dẫn" và giá trị là phần còn lại sau giá trị đầu tiên =.


3
+1 cho phương pháp phân tách, tránh sự xấu xí nhẹ của việc cắt thủ công trên len (tiền tố).
bobince

1
Nhưng cũng ném nếu đầu vào của bạn không ở dạng "cái gì đó = cái gì đó".
Dan Olson

1
Đó là lý do tại sao tôi đặt điều kiện ở phía trước để nó chỉ được sử dụng nếu "=" nằm trong chuỗi. Mặt khác, bạn cũng có thể kiểm tra độ dài của kết quả của split () và nếu đó là == 2.
MrTopf

7
Giống như Dan Olson nói splitném một ngoại lệ nếu không có dấu phân cách. partitionổn định hơn, nó cũng phân tách một chuỗi và luôn trả về một bộ ba phần tử với pre-, delimiter và post-content (một số có thể là ''nếu không có dấu phân cách). Ví dụ value = line.partition('=').
Anders Johansson

1
Split không ném ngoại lệ nếu không có giới hạn, nó sẽ trả về một danh sách với toàn bộ chuỗi. Ít nhất là dưới trăn 2.7
Maxim

122

Xóa tiền tố khỏi chuỗi

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

Tách vào lần xuất hiện đầu tiên của dải phân cách thông qua 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

Phân tích tệp tương tự INI với 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

Sự lựa chọn khác


1
Một lý do hiếm hoi để thụt ba không gian thay vì bốn.
Bob Stein

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

1
Tôi thích cái này vì bạn có thể thay thế "văn bản khác" bằng "other false" hoặc "other none" hoặc bất cứ thứ gì - bạn muốn quay lại để chỉ ra rằng dòng trong tệp không bắt đầu bằng "Path =". Cá nhân tôi thích bao quanh các toán tử ternary của mình với dấu ngoặc đơn để nổi bật trực quan.
DevPlayer 27/8/2016

19

Để cắt lát (có điều kiện hoặc không có điều kiện) nói chung tôi thích những gì một đồng nghiệp đề nghị gần đây; Sử dụng thay thế bằng một chuỗi rỗng. Dễ đọc mã hơn, ít mã hơn (đôi khi) và ít rủi ro chỉ định số lượng ký tự sai. Đồng ý; Tôi không sử dụng Python, nhưng trong các ngôn ngữ khác tôi thích cách tiếp cận này:

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

hoặc - để theo dõi bình luận đầu tiên cho bài đăng này - nếu điều này chỉ nên được thực hiện nếu dòng bắt đầu bằng Path:

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

Sự khác biệt chính đối với một số điều đã được đề xuất ở trên là không có "số ma thuật" (5) liên quan, cũng không cần chỉ định cả ' 5' chuỗi ' Path=', nói cách khác tôi thích cách tiếp cận này từ bảo trì mã quan điểm.


Nó không hoạt động: 'c = Path = a'.replace ("Path =", "", 1) ->' c = a '.
jfs

3
Điều đó không đáp ứng yêu cầu ban đầu của chuỗi bắt đầu bằng "Path =".
Cún con

1
Bạn có thể thay thế mã regex bằng chỉ rightmost = re.sub('^Path=', '', fullPath). Mục đích của compile()phương pháp là làm cho mọi thứ nhanh hơn nếu bạn sử dụng lại đối tượng đã biên dịch, nhưng vì bạn vứt nó đi sau khi bạn sử dụng nó, nên dù sao nó cũng không có tác dụng. Nó thường không đáng lo ngại về việc tối ưu hóa này.
Jim Oldfield

13

Tôi thích poplập chỉ mục [-1]:

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

đến

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

2
Đẹp thay thế mà không có "số ma thuật". Điều đáng chú ý là điều này hoạt động vì startswithđã được thử nghiệm nên splitsẽ phân chia "không có gì" trước và mọi thứ khác sau đó. split("Path=", 1)chính xác hơn (trong trường hợp tiền tố xuất hiện lại sau trong chuỗi) nhưng giới thiệu lại một số ma thuật.
quornian

1
Phiên bản ngắn hơn của nhận xét trước (rất quan trọng): điều này chỉ hoạt động nếu bạn kiểm tra với startedwith () trước.
MarcH

12

Hay tại sao không

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

5

Làm thế nào về..

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

Bộ ba này là đầu, dải phân cách và đuôi .


Điều này không hoạt động trong mọi trường hợp theo cùng một cách. Nếu có dấu phân cách thì kết quả là mục thứ ba. Nếu không, kết quả là mục đầu tiên.
Ioannis Filippidis

5

Cách đơn giản nhất tôi có thể nghĩ là cắt lát:

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

Một ghi chú nhanh về ký hiệu lát, nó sử dụng hai chỉ số thay vì thông thường. Chỉ mục đầu tiên cho biết phần tử đầu tiên của chuỗi bạn muốn đưa vào lát cắt và chỉ mục cuối cùng là chỉ mục ngay sau phần tử cuối cùng bạn muốn đưa vào lát.
Ví dụ:

sequence_obj[first_index:last_index]

Các lát cắt bao gồm tất cả các yếu tố giữa first_indexlast_index, bao gồm first_indexvà không last_index. Nếu chỉ mục đầu tiên bị bỏ qua, nó sẽ mặc định bắt đầu chuỗi. Nếu chỉ mục cuối cùng bị bỏ qua, nó bao gồm tất cả các phần tử cho đến phần tử cuối cùng trong chuỗi. Chỉ số tiêu cực cũng được cho phép. Sử dụng Google để tìm hiểu thêm về chủ đề.


4
>>> import re

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

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

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

1. Sử dụng r''chuỗi cho đường dẫn Windows. 2. re.match()có thể trả về Không
jfs

3

Một lớp lót đơn giản khác chưa được đề cập ở đây:

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

Điều này cũng sẽ hoạt động đúng cho các trường hợp cạnh khác nhau:

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

Nếu bạn biết cách hiểu danh sách:

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

Có một chỉnh sửa cho thấy line.startswith(...)nhanh hơn 10 lần. Thử nghiệm của tôi đã không xác nhận điều này. Rất vui được thay đổi nếu bằng chứng ủng hộ khẳng định đó được cung cấp.
Matthew Schinckel

0

Phiên bản nhạc pop không hoàn toàn đúng. Tôi nghĩ bạn muốn:

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

0

Tại sao không sử dụng regex với thoát? ^khớp với phần ban đầu của một dòng và re.MULTILINEkhớp trên mỗi dòng. re.escapeđảm bảo rằng sự phù hợp là chính xác.

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

0

Hãy thử theo dõi mã

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

1
Sự khác biệt giữa câu trả lời của bạn và câu trả lời được chấp nhận là gì? Tôi thấy rằng đó là trong phần đầu tiên của câu trả lời khác.
Eyllanesc

-1

Tôi đoán đây là những gì bạn đang tìm kiếm chính xác

    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

không cần phải viết hàm, cái này sẽ phân chia theo danh sách, trong trường hợp này là 'Ông | Tiến sĩ | Bà.', chọn mọi thứ sau khi tách bằng [1], sau đó phân tách lại và lấy bất kỳ phần tử nào. Trong trường hợp dưới đây, 'Morris' được trả lại.

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

-1

Kỹ thuật này rất giống với các câu trả lời khác, nhưng không có thao tác chuỗi lặp lại, khả năng cho biết tiền tố có ở đó hay không, và vẫn khá dễ đọc:

parts = the_string.split(prefix_to_remove, 1):
    if len(parts) == 2:
        #  do things with parts[1]
        pass
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.