Biến một chuỗi thành một tên tệp hợp lệ?


298

Tôi có một chuỗi mà tôi muốn sử dụng làm tên tệp, vì vậy tôi muốn xóa tất cả các ký tự không được phép trong tên tệp, sử dụng Python.

Tôi muốn nghiêm khắc hơn so với khác, vì vậy hãy nói rằng tôi chỉ muốn giữ lại các chữ cái, chữ số và một bộ nhỏ các ký tự khác như thế nào "_-.() ". Giải pháp thanh lịch nhất là gì?

Tên tệp cần phải hợp lệ trên nhiều hệ điều hành (Windows, Linux và Mac OS) - đó là tệp MP3 trong thư viện của tôi với tên bài hát là tên tệp và được chia sẻ và sao lưu giữa 3 máy.


17
Điều này có nên được xây dựng trong mô-đun os.path không?
endolith

2
Có lẽ, mặc dù trường hợp sử dụng của cô ấy sẽ yêu cầu một đường dẫn duy nhất an toàn trên tất cả các nền tảng, không chỉ đường dẫn hiện tại, đó là điều mà os.path không được thiết kế để xử lý.
javawizard

2
Để mở rộng nhận xét trên: thiết kế hiện tại os.paththực sự tải một thư viện khác tùy thuộc vào hệ điều hành (xem ghi chú thứ hai trong tài liệu ). Vì vậy, nếu chức năng trích dẫn được triển khai trong os.pathnó, chỉ có thể trích dẫn chuỗi về an toàn POSIX khi chạy trên hệ thống POSIX hoặc an toàn cho windows khi chạy trên windows. Tên tệp kết quả sẽ không nhất thiết phải hợp lệ trên cả hai cửa sổ và POSIX, đây là những gì câu hỏi yêu cầu.
dshepherd 10/03/2015

Câu trả lời:


164

Bạn có thể nhìn vào khung Django để biết cách họ tạo ra một "con sên" từ văn bản tùy ý. Một con sên là URL- và tên tệp- thân thiện.

Các dụng cụ văn bản Django xác định một chức năng slugify(), đó có lẽ là tiêu chuẩn vàng cho loại điều này. Về cơ bản, mã của họ là như sau.

def slugify(value):
    """
    Normalizes string, converts to lowercase, removes non-alpha characters,
    and converts spaces to hyphens.
    """
    import unicodedata
    value = unicodedata.normalize('NFKD', value).encode('ascii', 'ignore')
    value = unicode(re.sub('[^\w\s-]', '', value).strip().lower())
    value = unicode(re.sub('[-\s]+', '-', value))
    # ...
    return value

Có nhiều hơn, nhưng tôi đã bỏ nó đi, vì nó không giải quyết vấn đề sên, nhưng thoát ra.


11
Dòng cuối cùng phải là: value = unicode (re.sub ('[- \ s] +', '-', value))
Joseph Turian

1
Cảm ơn - Tôi có thể thiếu một cái gì đó, nhưng tôi nhận được: "normalize () argument 2 phải là unicode, không phải str"
Alex Cook

"bình thường hóa () đối số 2". Có nghĩa là value. Nếu giá trị phải là Unicode, thì bạn phải chắc chắn rằng đó thực sự là Unicode. Hoặc là. Bạn có thể muốn loại bỏ chuẩn hóa unicode nếu giá trị thực của bạn thực sự là một chuỗi ASCII.
S.Lott

8
Trong trường hợp bất kỳ ai không nhận thấy mặt tích cực của phương pháp này là nó không chỉ loại bỏ các ký tự không phải alpha, mà là cố gắng tìm các thay thế tốt trước tiên (thông qua chuẩn hóa NFKD), vì vậy é trở thành e, siêu ký tự 1 trở thành bình thường 1, v.v ... Cảm ơn
Michael Scott Cuthbert

48
Các slugifychức năng đã được chuyển đến django / utils / text.py , và tập tin đó cũng chứa một get_valid_filenamehàm.
Denilson Sá Maia

104

Cách tiếp cận danh sách trắng này (nghĩa là chỉ cho phép các ký tự có trong valid_chars) sẽ hoạt động nếu không có giới hạn về định dạng của các tệp hoặc kết hợp các ký tự hợp lệ là bất hợp pháp (như ".."), ví dụ như những gì bạn nói sẽ cho phép một tên tệp có tên ". txt" mà tôi nghĩ là không hợp lệ trên Windows. Vì đây là cách tiếp cận đơn giản nhất mà tôi cố gắng xóa khoảng trắng khỏi valid_chars và thêm vào một chuỗi hợp lệ đã biết trong trường hợp có lỗi, bất kỳ cách tiếp cận nào khác sẽ phải biết về những gì được phép đối phó với các giới hạn đặt tên tệp của Windows và do đó phức tạp hơn nhiều

>>> import string
>>> valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits)
>>> valid_chars
'-_.() abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
>>> filename = "This Is a (valid) - filename%$&$ .txt"
>>> ''.join(c for c in filename if c in valid_chars)
'This Is a (valid) - filename .txt'

7
valid_chars = frozenset(valid_chars)sẽ không đau Nó nhanh hơn 1,5 lần nếu áp dụng cho allchars.
jfs

2
Cảnh báo: Điều này ánh xạ hai chuỗi khác nhau vào cùng một chuỗi >>> nhập chuỗi >>> valid_chars = "- . ()% S% s"% (string.ascii_letters, string.digits) >>> valid_chars '- . () abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 '>>> filename = "a.com/hello/world" >>>' '.join (c cho c trong tên tệp nếu c trong tên tập tin " ">>> '' .join (c cho c trong tên tệp nếu c trong valid_chars) 'a.comhellowworld' >>>
vua robert

3
Chưa kể đến việc đặt tên một tệp "CON"trên Windows sẽ khiến bạn gặp rắc rối ...
Nathan Osman

2
Một sự sắp xếp lại nhẹ làm cho việc chỉ định một nhân vật thay thế đơn giản. Đầu tiên là chức năng ban đầu: '' .join (c if c in valid_chars other '' cho c trong tên tệp) hoặc với một ký tự hoặc chuỗi được thay thế cho mọi ký tự không hợp lệ: '' .join (c if c in valid_chars other '.' c trong tên tệp)
PeterVermont

101

Bạn có thể sử dụng hiểu danh sách cùng với các phương thức chuỗi.

>>> s
'foo-bar#baz?qux@127/\\9]'
>>> "".join(x for x in s if x.isalnum())
'foobarbazqux1279'

3
Lưu ý rằng bạn có thể bỏ qua dấu ngoặc vuông. Trong trường hợp này, một biểu thức trình tạo được chuyển qua để tham gia, giúp lưu bước tạo danh sách không sử dụng.
Oben Sonne

31
+1 Yêu thích điều này. Sửa đổi nhẹ tôi đã thực hiện: "" .join ([x if x.isalnum () other "_" cho x in s]) - sẽ mang lại kết quả trong đó các mục không hợp lệ là _, giống như chúng bị xóa trắng. Có lẽ tha cho người khác.
Eddie Parker

12
Giải pháp này thật tuyệt! Tôi đã thực hiện một sửa đổi nhỏ mặc dù:filename = "".join(i for i in s if i not in "\/:*?<>|")
Alex Krycek

1
Thật không may, nó thậm chí không cho phép không gian và dấu chấm, nhưng tôi thích ý tưởng này.
tiktak

9
@tiktak: to (cũng) cho phép khoảng trắng, dấu chấm và dấu gạch dưới mà bạn có thể sử dụng"".join( x for x in s if (x.isalnum() or x in "._- "))
hardmooth

95

Lý do để sử dụng các chuỗi như tên tập tin là gì? Nếu khả năng đọc của con người không phải là một yếu tố tôi sẽ đi với mô-đun base64 có thể tạo ra chuỗi an toàn cho hệ thống tệp. Nó sẽ không thể đọc được nhưng bạn sẽ không phải đối phó với các va chạm và nó có thể đảo ngược.

import base64
file_name_string = base64.urlsafe_b64encode(your_string)

Cập nhật : Thay đổi dựa trên bình luận của Matthew.


1
Rõ ràng đây là câu trả lời tốt nhất nếu đó là trường hợp.
dùng32141

60
Cảnh báo! Mã hóa base64 theo mặc định bao gồm ký tự "/" là đầu ra hợp lệ không hợp lệ trong tên tệp trên nhiều hệ thống. Thay vào đó, hãy sử dụng base64.urlsafe_b64encode (your_ chuỗi)
Matthew

15
Trên thực tế khả năng đọc của con người hầu như luôn là một yếu tố, ngay cả khi chỉ nhằm mục đích gỡ lỗi.
static_rtti

5
Trong Python 3 your_stringcần phải là một mảng byte hoặc kết quả của encode('ascii')việc này để làm việc.
Noumenon

4
def url2filename(url): url = url.encode('UTF-8') return base64.urlsafe_b64encode(url).decode('UTF-8') def filename2url(f): return base64.urlsafe_b64decode(f).decode('UTF-8')
JeffProd

40

Chỉ cần làm phức tạp thêm mọi thứ, bạn không được đảm bảo có được tên tệp hợp lệ chỉ bằng cách xóa các ký tự không hợp lệ. Vì các ký tự được phép khác nhau trên các tên tệp khác nhau, nên một cách tiếp cận bảo thủ có thể sẽ biến một tên hợp lệ thành một tên không hợp lệ. Bạn có thể muốn thêm xử lý đặc biệt cho các trường hợp:

  • Chuỗi là tất cả các ký tự không hợp lệ (để lại cho bạn một chuỗi trống)

  • Bạn kết thúc bằng một chuỗi có ý nghĩa đặc biệt, ví dụ "." hoặc là ".."

  • Trên cửa sổ, một số tên thiết bị được bảo lưu. Chẳng hạn, bạn không thể tạo một tệp có tên "nul", "nul.txt" (hoặc thực tế là nul.anything) Các tên dành riêng là:

    CON, PRN, AUX, NUL, COM1, COM2, COM3, COM4, ​​COM5, COM6, COM7, COM8, COM9, LPT1, LPT2, LPT3, LPT4, LPT5, LPT6, LPT7, LPT8, LPT

Bạn có thể có thể giải quyết các vấn đề này bằng cách thêm một số chuỗi vào tên tệp không bao giờ có thể dẫn đến một trong những trường hợp này và tước các ký tự không hợp lệ.


24

Có một dự án hay trên Github có tên python-slugify :

Tải về:

pip install python-slugify

Sau đó sử dụng:

>>> from slugify import slugify
>>> txt = "This\ is/ a%#$ test ---"
>>> slugify(txt)
'this-is-a-test'

2
Tôi thích thư viện này nhưng nó không tốt như tôi nghĩ. Thử nghiệm ban đầu ok nhưng nó cũng chuyển đổi dấu chấm. Vì vậy, test.txtcó được test-txtđó là quá nhiều.
Therealmarv

23

Giống như S.Lott đã trả lời, bạn có thể xem Django Framework để biết cách họ chuyển đổi một chuỗi thành tên tệp hợp lệ.

Phiên bản mới nhất và được cập nhật được tìm thấy trong utils / text.py và định nghĩa "get_valid_filename", như sau:

def get_valid_filename(s):
    s = str(s).strip().replace(' ', '_')
    return re.sub(r'(?u)[^-\w.]', '', s)

(Xem https://github.com/django/django/blob/master/django/utils/text.py )


4
cho sự lười biếng đã có trên django:django.utils.text import get_valid_filename
theannouncer

2
Trong trường hợp bạn không quen thuộc với regex, hãy re.sub(r'(?u)[^-\w.]', '', s)xóa tất cả các ký tự không phải là chữ cái, không phải số (0-9), không phải dấu gạch dưới ('_'), không phải dấu gạch ngang ('-') và không phải dấu chấm ('.' ). "Chữ cái" ở đây bao gồm tất cả các chữ cái unicode, chẳng hạn như.
chăn bò

3
Bạn cũng có thể muốn kiểm tra độ dài: Tên tệp được giới hạn ở 255 ký tự (hoặc, bạn biết, 32; tùy thuộc vào FS)
Matthias Winkelmann

19

Đây là giải pháp cuối cùng tôi đã sử dụng:

import unicodedata

validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits)

def removeDisallowedFilenameChars(filename):
    cleanedFilename = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore')
    return ''.join(c for c in cleanedFilename if c in validFilenameChars)

Cuộc gọi unicodingata.n normalize thay thế các ký tự có dấu bằng tương đương không có dấu, tốt hơn là chỉ đơn giản là tước chúng ra. Sau đó, tất cả các ký tự không được phép được loại bỏ.

Giải pháp của tôi không cung cấp một chuỗi đã biết để tránh các tên tệp không được phép, bởi vì tôi biết chúng không thể xảy ra với định dạng tên tệp cụ thể của tôi. Một giải pháp tổng quát hơn sẽ cần phải làm như vậy.


bạn sẽ có thể sử dụng uuid.uuid4 () cho tiền tố duy nhất của mình
slf

6
trường hợp lạc đà .. ahh
con nhím mất trí nhớ

Điều này có thể được chỉnh sửa / cập nhật để làm việc với Python 3.6 không?
Wavesailor

13

Hãy nhớ rằng, thực sự không có hạn chế nào đối với tên tệp trên các hệ thống Unix ngoài

  • Nó có thể không chứa \ 0
  • Nó có thể không chứa /

Mọi thứ khác đều công bằng.

$ chạm "
> thậm chí đa dòng
> haha
> ^ [[31m đỏ ^ [[0m
> ác "
$ ls -la 
-rw-r - r-- 0 ngày 17 tháng 11 23:39? thậm chí đa dòng? haha ​​?? [31m đỏ? [0m? ác
$ ls -lab
-rw-r - r-- 0 ngày 17 tháng 11 23:39 \ neven \ multiline \ nhaha \ n \ 033 [31m \ red \ \ 033 [0m \ nevil
$ perl -e 'cho $ i của tôi (global (q {./* thậm chí *})) {print $ i; } '
./
thậm chí đa dòng
haha
 màu đỏ 
tà ác

Có, tôi chỉ lưu mã màu ANSI trong một tên tệp và chúng có hiệu lực.

Để giải trí, hãy đặt một ký tự BEL vào tên thư mục và xem những điều thú vị xảy ra khi bạn đưa CD vào đó;)


OP tuyên bố rằng "Tên tệp cần phải hợp lệ trên nhiều hệ điều hành"
cowlinator

1
@cowlinator rằng làm rõ đã được thêm 10 giờ sau khi câu trả lời của tôi được đăng :) Kiểm tra nhật ký chỉnh sửa của OP.
Kent Fredric

12

Trong một dòng:

valid_file_name = re.sub('[^\w_.)( -]', '', any_string)

bạn cũng có thể đặt ký tự '_' để dễ đọc hơn (ví dụ trong trường hợp thay thế dấu gạch chéo)


7

Bạn có thể sử dụng phương thức re.sub () để thay thế bất cứ thứ gì không "filelike". Nhưng thực tế, mọi nhân vật đều có thể hợp lệ; vì vậy không có chức năng dựng sẵn (tôi tin), để hoàn thành nó.

import re

str = "File!name?.txt"
f = open(os.path.join("/tmp", re.sub('[^-a-zA-Z0-9_.() ]+', '', str))

Sẽ dẫn đến một tập tin thành /tmp/filename.txt.


5
Bạn cần dấu gạch ngang để đi đầu tiên trong trình so khớp nhóm để nó không xuất hiện dưới dạng phạm vi. re.sub ('[^ - a-zA-Z0-9 _. ()] +', '', str)
phord

7
>>> import string
>>> safechars = bytearray(('_-.()' + string.digits + string.ascii_letters).encode())
>>> allchars = bytearray(range(0x100))
>>> deletechars = bytearray(set(allchars) - set(safechars))
>>> filename = u'#ab\xa0c.$%.txt'
>>> safe_filename = filename.encode('ascii', 'ignore').translate(None, deletechars).decode()
>>> safe_filename
'abc..txt'

Nó không xử lý các chuỗi rỗng, tên tệp đặc biệt ('nul', 'con', v.v.).


+1 cho các bảng dịch, đây là phương pháp hiệu quả nhất. Đối với tên tệp / empties đặc biệt, kiểm tra tiền điều kiện đơn giản sẽ đủ và trong các giai đoạn không liên quan cũng là một sự điều chỉnh đơn giản.
Christian Witts

1
Mặc dù dịch hiệu quả hơn một chút so với regrec, nhưng thời gian đó rất có thể sẽ bị lùn đi nếu bạn thực sự cố gắng mở tệp, điều mà không nghi ngờ gì là bạn đang có ý định làm. Vì vậy, tôi thích một giải pháp
regrec

Tôi cũng lo lắng về danh sách đen. Cấp, đó là một danh sách đen dựa trên danh sách trắng, nhưng vẫn còn. Có vẻ như ít ... an toàn. Làm thế nào để bạn biết rằng "allchars" đã thực sự hoàn thành?
isaaclw

@isaaclw: '.translate ()' chấp nhận chuỗi 256-char làm bảng dịch (dịch theo từng byte). '.Maketrans ()' tạo ra chuỗi như vậy. Tất cả các giá trị được bảo hiểm; đó là một cách tiếp cận danh sách trắng thuần túy
jfs

Còn tên tệp '.' (một dấu chấm đơn). Điều đó sẽ không hoạt động trên Unix vì thư mục hiện tại đang sử dụng tên đó.
Finn Årup Nielsen

6

Mặc dù bạn phải cẩn thận. Nó không được nói rõ ràng trong phần giới thiệu của bạn, nếu bạn chỉ nhìn vào ngôn ngữ latine. Một số từ có thể trở nên vô nghĩa hoặc có nghĩa khác nếu bạn vệ sinh chúng chỉ bằng các ký tự ascii.

hãy tưởng tượng bạn có "forêt poésie" (thơ rừng), việc vệ sinh của bạn có thể cho "fort-posie" (mạnh + một cái gì đó vô nghĩa)

Tệ hơn nếu bạn phải đối phó với các nhân vật Trung Quốc.

"下 北" hệ thống của bạn có thể sẽ kết thúc "---", điều này chắc chắn sẽ thất bại sau một thời gian và không hữu ích lắm. Vì vậy, nếu bạn chỉ xử lý các tệp, tôi sẽ khuyến khích gọi chúng là một chuỗi chung mà bạn kiểm soát hoặc giữ các ký tự như hiện tại. Đối với URI, về cùng.


6

Tại sao không chỉ bọc "osopen" bằng một thử / ngoại trừ và để hệ điều hành cơ bản sắp xếp xem liệu tệp có hợp lệ không?

Điều này có vẻ như ít công việc hơn và hợp lệ cho dù bạn sử dụng hệ điều hành nào.


5
Liệu nó có hợp lệ tên mặc dù? Ý tôi là, nếu HĐH không hài lòng, thì bạn vẫn cần phải làm gì đó, phải không?
jeromej

1
Trong một số trường hợp, HĐH / Ngôn ngữ có thể âm thầm chuyển tên tệp của bạn sang một hình thức thay thế, nhưng khi bạn thực hiện một danh sách thư mục, bạn sẽ nhận được một tên khác. Và điều này có thể dẫn đến một vấn đề "khi tôi viết tệp ở đó, nhưng khi tôi tìm tệp thì nó được gọi là vấn đề khác". (Tôi đang nói về hành vi mà tôi đã nghe về VAX ...)
Kent Fredric

Ngoài ra, "Tên tệp cần phải hợp lệ trên nhiều hệ điều hành" mà bạn không thể phát hiện khi osopenchạy trên một máy.
LarsH

5

Một vấn đề khác mà các bình luận khác chưa giải quyết được là chuỗi rỗng, rõ ràng đây không phải là tên tệp hợp lệ. Bạn cũng có thể kết thúc bằng một chuỗi trống từ việc tước quá nhiều ký tự.

Điều gì với tên tệp dành riêng của Windows và các vấn đề với dấu chấm, câu trả lời an toàn nhất cho câu hỏi Làm thế nào để tôi bình thường hóa tên tệp hợp lệ từ đầu vào của người dùng tùy ý? Là một người thậm chí không bận tâm đến việc dùng thử: nếu bạn có thể tìm bất kỳ cách nào khác để tránh điều đó (ví dụ: sử dụng các khóa chính nguyên từ cơ sở dữ liệu dưới dạng tên tệp), hãy làm điều đó.

Nếu bạn phải, và bạn thực sự cần phải cho phép không gian và '.' để mở rộng tập tin như một phần của tên, hãy thử một cái gì đó như:

import re
badchars= re.compile(r'[^A-Za-z0-9_. ]+|^\.|\.$|^ | $|^$')
badnames= re.compile(r'(aux|com[1-9]|con|lpt[1-9]|prn)(\.|$)')

def makeName(s):
    name= badchars.sub('_', s)
    if badnames.match(name):
        name= '_'+name
    return name

Ngay cả điều này cũng không thể được đảm bảo ngay cả trên các HĐH không mong muốn - ví dụ: HĐH RISC ghét không gian và sử dụng '.' như một dấu phân cách thư mục.


4

Tôi thích cách tiếp cận slugify python ở đây nhưng nó đã bị tước đi những dấu chấm không mong muốn. Vì vậy, tôi đã tối ưu hóa nó để tải tên tệp sạch lên s3 theo cách này:

pip install python-slugify

Mã ví dụ:

s = 'Very / Unsafe / file\nname hähä \n\r .txt'
clean_basename = slugify(os.path.splitext(s)[0])
clean_extension = slugify(os.path.splitext(s)[1][1:])
if clean_extension:
    clean_filename = '{}.{}'.format(clean_basename, clean_extension)
elif clean_basename:
    clean_filename = clean_basename
else:
    clean_filename = 'none' # only unclean characters

Đầu ra:

>>> clean_filename
'very-unsafe-file-name-haha.txt'

Điều này rất không an toàn, nó hoạt động với tên tệp không có phần mở rộng và thậm chí nó chỉ hoạt động với tên tệp ký tự không an toàn (kết quả là noneở đây).


1
Tôi thích điều này, không phát minh lại bánh xe, không nhập toàn bộ khung Django nếu bạn không cần nó, không dán trực tiếp mã nếu bạn sẽ không duy trì nó trong tương lai và tạo chuỗi thử để khớp các chữ cái tương tự với các chữ cái an toàn, vì vậy chuỗi mới dễ đọc hơn.
Abbeyenteherrera

1
Để sử dụng dấu gạch dưới thay vì dấu gạch ngang: name = slugify (s, separator = '_')
Abbeyenteherrera

3

Trả lời sửa đổi cho python 3.6

import string
import unicodedata

validFilenameChars = "-_.() %s%s" % (string.ascii_letters, string.digits)
def removeDisallowedFilenameChars(filename):
    cleanedFilename = unicodedata.normalize('NFKD', filename).encode('ASCII', 'ignore')
    return ''.join(chr(c) for c in cleanedFilename if chr(c) in validFilenameChars)

Bạn có thể giải thích chi tiết câu trả lời của bạn?
thanh thản

Đó là câu trả lời tương tự được chấp nhận bởi Sophie Gage. Nhưng nó đã được sửa đổi để hoạt động trên python 3.6
Jean-Robin Tremblay

2

Tôi nhận ra có rất nhiều câu trả lời nhưng chúng chủ yếu dựa vào các biểu thức thông thường hoặc các mô-đun bên ngoài, vì vậy tôi muốn đưa ra câu trả lời của riêng mình. Một hàm python thuần, không cần mô-đun bên ngoài, không sử dụng biểu thức chính quy. Cách tiếp cận của tôi không phải là làm sạch các ký tự không hợp lệ, mà chỉ cho phép các ký tự hợp lệ.

def normalizefilename(fn):
    validchars = "-_.() "
    out = ""
    for c in fn:
      if str.isalpha(c) or str.isdigit(c) or (c in validchars):
        out += c
      else:
        out += "_"
    return out    

nếu bạn thích, bạn có thể thêm ký tự hợp lệ của riêng bạn vào validcharsbiến ở đầu, chẳng hạn như các chữ cái quốc gia của bạn không tồn tại trong bảng chữ cái tiếng Anh. Đây là điều bạn có thể hoặc không muốn: một số hệ thống tệp không chạy trên UTF-8 vẫn có thể gặp sự cố với ký tự không phải ASCII.

Hàm này là để kiểm tra tính hợp lệ của một tên tệp, do đó, nó sẽ thay thế các dấu tách đường dẫn bằng _ coi chúng là các ký tự không hợp lệ. Nếu bạn muốn thêm nó, việc sửa đổi ifdấu phân tách đường dẫn os là không quan trọng.


1

Hầu hết các giải pháp này không hoạt động.

'/ xin chào / thế giới' -> 'hellowworld'

'/ hellowworld' / -> 'hellowworld'

Đây không phải là những gì bạn muốn nói chung, giả sử bạn đang lưu html cho mỗi liên kết, bạn sẽ ghi đè lên html cho một trang web khác.

Tôi chọn một lệnh như:

{'helloworld': 
    (
    {'/hello/world': 'helloworld', '/helloworld/': 'helloworld1'},
    2)
    }

2 đại diện cho số nên được thêm vào tên tệp tiếp theo.

Tôi tìm tên tập tin mỗi lần từ dict. Nếu nó không ở đó, tôi tạo một cái mới, nối thêm số tối đa nếu cần.


lưu ý, nếu sử dụng hellowworld1, bạn cũng cần kiểm tra hellowworld1 không được sử dụng, v.v.
robert king

1

Không chính xác những gì OP đã yêu cầu nhưng đây là những gì tôi sử dụng vì tôi cần các chuyển đổi độc đáo và có thể đảo ngược:

# p3 code
def safePath (url):
    return ''.join(map(lambda ch: chr(ch) if ch in safePath.chars else '%%%02x' % ch, url.encode('utf-8')))
safePath.chars = set(map(lambda x: ord(x), '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+-_ .'))

Kết quả là "hơi" có thể đọc được, ít nhất là từ quan điểm sysadmin.


Một trình bao bọc cho điều này không có khoảng trắng trong tên tệp:def safe_filename(filename): return safePath(filename.strip().replace(' ','_'))
SpeedCoder5

1

Nếu bạn không nhớ cài đặt một gói, điều này sẽ hữu ích: https://pypi.org/project/pathvalidate/

Từ https://pypi.org/project/pathvalidate/#sanitize-a-filename :

from pathvalidate import sanitize_filename

fname = "fi:l*e/p\"a?t>h|.t<xt"
print(f"{fname} -> {sanitize_filename(fname)}\n")
fname = "\0_a*b:c<d>e%f/(g)h+i_0.txt"
print(f"{fname} -> {sanitize_filename(fname)}\n")

Đầu ra

fi:l*e/p"a?t>h|.t<xt -> filepath.txt
_a*b:c<d>e%f/(g)h+i_0.txt -> _abcde%f(g)h+i_0.txt

0

Tôi chắc chắn đây không phải là một câu trả lời hay, vì nó sửa đổi chuỗi mà nó lặp lại, nhưng dường như nó hoạt động ổn:

import string
for chr in your_string:
 if chr == ' ':
   your_string = your_string.replace(' ', '_')
 elif chr not in string.ascii_letters or chr not in string.digits:
    your_string = your_string.replace(chr, '')

Tôi đã tìm thấy điều này "".join( x for x in s if (x.isalnum() or x in "._- "))trên bình luận bài đăng này
SergioAraujo

0

CẬP NHẬT

Tất cả các liên kết bị hỏng ngoài sửa chữa trong câu trả lời 6 tuổi này.

Ngoài ra, tôi cũng sẽ không làm theo cách này nữa, chỉ base64mã hóa hoặc thả các ký tự không an toàn. Ví dụ về Python 3:

import re
t = re.compile("[a-zA-Z0-9.,_-]")
unsafe = "abc∂éåß®∆˚˙©¬ñ√ƒµ©∆∫ø"
safe = [ch for ch in unsafe if t.match(ch)]
# => 'abc'

Với base64 bạn có thể mã hóa và giải mã, do đó bạn có thể lấy lại tên tệp gốc.

Nhưng tùy thuộc vào trường hợp sử dụng, bạn có thể tốt hơn là tạo một tên tệp ngẫu nhiên và lưu trữ siêu dữ liệu trong tệp hoặc DB riêng biệt.

from random import choice
from string import ascii_lowercase, ascii_uppercase, digits
allowed_chr = ascii_lowercase + ascii_uppercase + digits

safe = ''.join([choice(allowed_chr) for _ in range(16)])
# => 'CYQ4JDKE9JfcRzAZ'

LIÊN KẾT LIÊN KẾT GỐC :

Các bobcat dự án có chứa một mô-đun python mà chỉ này.

Nó không hoàn toàn mạnh mẽ, xem bài đăng này và trả lời này .

Vì vậy, như đã lưu ý: base64mã hóa có lẽ là một ý tưởng tốt hơn nếu khả năng đọc không thành vấn đề.


Tất cả các liên kết chết. Người đàn ông, làm một cái gì đó.
Bộ giải mã hòa bình
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.