Chương trình của tôi sẽ lấy các chuỗi tùy ý từ internet và sử dụng chúng cho tên tệp. Có cách nào đơn giản để xóa các ký tự xấu khỏi các chuỗi này hay tôi cần viết một hàm tùy chỉnh cho việc này?
Chương trình của tôi sẽ lấy các chuỗi tùy ý từ internet và sử dụng chúng cho tên tệp. Có cách nào đơn giản để xóa các ký tự xấu khỏi các chuỗi này hay tôi cần viết một hàm tùy chỉnh cho việc này?
Câu trả lời:
Ugh, tôi ghét khi mọi người cố đoán xem ký tự nào hợp lệ. Bên cạnh việc hoàn toàn không di động (luôn nghĩ về Mono), cả hai bình luận trước đó đều bỏ sót thêm 25 ký tự không hợp lệ.
'Clean just a filename
Dim filename As String = "salmnas dlajhdla kjha;dmas'lkasn"
For Each c In IO.Path.GetInvalidFileNameChars
filename = filename.Replace(c, "")
Next
'See also IO.Path.GetInvalidPathChars
Để loại bỏ các ký tự không hợp lệ:
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars
var validFilename = new string(filename.Where(ch => !invalidFileNameChars.Contains(ch)).ToArray());
Để thay thế các ký tự không hợp lệ:
static readonly char[] invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars and an _ for invalid ones
var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? '_' : ch).ToArray());
Để thay thế các ký tự không hợp lệ (và tránh xung đột tên tiềm ẩn như Hell * vs Hell $):
static readonly IList<char> invalidFileNameChars = Path.GetInvalidFileNameChars();
// Builds a string out of valid chars and replaces invalid chars with a unique letter (Moves the Char into the letter range of unicode, starting at "A")
var validFilename = new string(filename.Select(ch => invalidFileNameChars.Contains(ch) ? Convert.ToChar(invalidFileNameChars.IndexOf(ch) + 65) : ch).ToArray());
Câu hỏi này đã được hỏi nhiều lần trước đây và như đã chỉ ra nhiều lần trước đây, IO.Path.GetInvalidFileNameChars
là không đầy đủ.
Đầu tiên, có nhiều tên như PRN và CON được dành riêng và không được phép đặt cho tên tệp. Có những tên khác không được phép chỉ ở thư mục gốc. Tên kết thúc bằng dấu chấm cũng không được phép.
Thứ hai, có nhiều giới hạn về độ dài. Đọc danh sách đầy đủ cho NTFS ở đây .
Thứ ba, bạn có thể đính kèm vào các hệ thống tệp có những hạn chế khác. Ví dụ: tên tệp ISO 9660 không thể bắt đầu bằng "-" nhưng có thể chứa nó.
Thứ tư, bạn sẽ làm gì nếu hai tiến trình "tự ý" chọn cùng một tên?
Nói chung, sử dụng tên được tạo từ bên ngoài cho tên tệp là một ý tưởng tồi. Tôi khuyên bạn nên tạo các tên tệp riêng tư của riêng bạn và lưu trữ các tên có thể đọc được trong nội bộ.
Tôi đồng ý với Grauenwolf và rất muốn giới thiệu Path.GetInvalidFileNameChars()
Đây là đóng góp C # của tôi:
string file = @"38?/.\}[+=n a882 a.a*/|n^%$ ad#(-))";
Array.ForEach(Path.GetInvalidFileNameChars(),
c => file = file.Replace(c.ToString(), String.Empty));
ps - điều này khó hiểu hơn nó nên làm - tôi đã cố gắng ngắn gọn.
Array.ForEach
thay vì chỉ foreach
ở đây
Path.GetInvalidFileNameChars().Aggregate(file, (current, c) => current.Replace(c, '-'))
Đây là phiên bản của tôi:
static string GetSafeFileName(string name, char replace = '_') {
char[] invalids = Path.GetInvalidFileNameChars();
return new string(name.Select(c => invalids.Contains(c) ? replace : c).ToArray());
}
Tôi không chắc kết quả của GetInvalidFileNameChars được tính như thế nào, nhưng "Get" cho thấy nó không tầm thường, vì vậy tôi lưu kết quả vào bộ nhớ cache. Hơn nữa, điều này chỉ duyệt chuỗi đầu vào một lần thay vì nhiều lần, giống như các giải pháp ở trên lặp lại tập hợp các ký tự không hợp lệ, thay thế chúng trong chuỗi nguồn tại một thời điểm. Ngoài ra, tôi thích các giải pháp Dựa trên vị trí, nhưng tôi thích thay thế các ký tự không hợp lệ thay vì xóa chúng. Cuối cùng, sự thay thế của tôi là chính xác một ký tự để tránh chuyển đổi ký tự thành chuỗi khi tôi lặp qua chuỗi.
Tôi nói tất cả những gì đang làm trong hồ sơ - điều này tôi cảm thấy rất tuyệt. :)
new HashSet<char>(Path.GetInvalidFileNameChars())
để tránh liệt kê O (n) - tối ưu hóa vi mô.
Đây là hàm mà tôi đang sử dụng bây giờ (cảm ơn jcollum về ví dụ C #):
public static string MakeSafeFilename(string filename, char replaceChar)
{
foreach (char c in System.IO.Path.GetInvalidFileNameChars())
{
filename = filename.Replace(c, replaceChar);
}
return filename;
}
Tôi chỉ đặt điều này trong một lớp "Người trợ giúp" để thuận tiện.
Nếu bạn muốn nhanh chóng loại bỏ tất cả các ký tự đặc biệt mà đôi khi người dùng dễ đọc hơn đối với tên tệp, điều này hoạt động tốt:
string myCrazyName = "q`w^e!r@t#y$u%i^o&p*a(s)d_f-g+h=j{k}l|z:x\"c<v>b?n[m]q\\w;e'r,t.y/u";
string safeName = Regex.Replace(
myCrazyName,
"\W", /*Matches any nonword character. Equivalent to '[^A-Za-z0-9_]'*/
"",
RegexOptions.IgnoreCase);
// safeName == "qwertyuiopasd_fghjklzxcvbnmqwertyu"
\W
khớp với nhiều hơn các số không phải chữ cái ( [^A-Za-z0-9_]
). Tất cả các ký tự 'từ' Unicode (русский 中文 ..., v.v.) cũng sẽ không được thay thế. Nhưng đây là một điều tốt.
.
vì vậy bạn phải giải nén phần mở rộng trước và thêm lại sau.
static class Utils
{
public static string MakeFileSystemSafe(this string s)
{
return new string(s.Where(IsFileSystemSafe).ToArray());
}
public static bool IsFileSystemSafe(char c)
{
return !Path.GetInvalidFileNameChars().Contains(c);
}
}
Tại sao không chuyển đổi chuỗi thành một chuỗi tương đương Base64 như thế này:
string UnsafeFileName = "salmnas dlajhdla kjha;dmas'lkasn";
string SafeFileName = Convert.ToBase64String(Encoding.UTF8.GetBytes(UnsafeFileName));
Nếu bạn muốn chuyển đổi nó trở lại để bạn có thể đọc nó:
UnsafeFileName = Encoding.UTF8.GetString(Convert.FromBase64String(SafeFileName));
Tôi đã sử dụng điều này để lưu các tệp PNG với một tên duy nhất từ một mô tả ngẫu nhiên.
Đây là những gì tôi vừa thêm vào lớp tĩnh StringExtensions của ClipFlair ( http://github.com/Zoomicon/ClipFlair ) (dự án Utils.Silverlight), dựa trên thông tin thu thập từ các liên kết đến các câu hỏi liên quan đến stackoverflow được đăng bởi Dour High Arch ở trên:
public static string ReplaceInvalidFileNameChars(this string s, string replacement = "")
{
return Regex.Replace(s,
"[" + Regex.Escape(new String(System.IO.Path.GetInvalidPathChars())) + "]",
replacement, //can even use a replacement string of any length
RegexOptions.IgnoreCase);
//not using System.IO.Path.InvalidPathChars (deprecated insecure API)
}
private void textBoxFileName_KeyPress(object sender, KeyPressEventArgs e)
{
e.Handled = CheckFileNameSafeCharacters(e);
}
/// <summary>
/// This is a good function for making sure that a user who is naming a file uses proper characters
/// </summary>
/// <param name="e"></param>
/// <returns></returns>
internal static bool CheckFileNameSafeCharacters(System.Windows.Forms.KeyPressEventArgs e)
{
if (e.KeyChar.Equals(24) ||
e.KeyChar.Equals(3) ||
e.KeyChar.Equals(22) ||
e.KeyChar.Equals(26) ||
e.KeyChar.Equals(25))//Control-X, C, V, Z and Y
return false;
if (e.KeyChar.Equals('\b'))//backspace
return false;
char[] charArray = Path.GetInvalidFileNameChars();
if (charArray.Contains(e.KeyChar))
return true;//Stop the character from being entered into the control since it is non-numerical
else
return false;
}
Tôi thấy việc sử dụng này sẽ nhanh chóng và dễ hiểu:
<Extension()>
Public Function MakeSafeFileName(FileName As String) As String
Return FileName.Where(Function(x) Not IO.Path.GetInvalidFileNameChars.Contains(x)).ToArray
End Function
Điều này hoạt động bởi vì a string
là IEnumerable
một char
mảng và có một string
chuỗi phương thức khởi tạo nhận một char
mảng.
Từ các dự án cũ của tôi, tôi đã tìm ra giải pháp này, đã hoạt động hoàn hảo trong hơn 2 năm. Tôi đang thay thế các ký tự bất hợp pháp bằng "!", Và sau đó kiểm tra các ký tự kép !!, sử dụng ký tự của riêng bạn.
public string GetSafeFilename(string filename)
{
string res = string.Join("!", filename.Split(Path.GetInvalidFileNameChars()));
while (res.IndexOf("!!") >= 0)
res = res.Replace("!!", "!");
return res;
}
Nhiều người đề nghị sử dụng Path.GetInvalidFileNameChars()
mà có vẻ như là một giải pháp tồi đối với tôi. Tôi khuyến khích bạn sử dụng danh sách trắng thay vì danh sách đen vì cuối cùng tin tặc sẽ luôn tìm ra cách để vượt qua nó.
Đây là một ví dụ về mã bạn có thể sử dụng:
string whitelist = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ.";
foreach (char c in filename)
{
if (!whitelist.Contains(c))
{
filename = filename.Replace(c, '-');
}
}