पथ और फ़ाइल नाम से अवैध वर्ण कैसे निकालें?


456

मुझे अवैध रास्ते को हटाने और एक साधारण स्ट्रिंग से पात्रों को फाइल करने के लिए एक मजबूत और सरल तरीके की आवश्यकता है। मैंने नीचे दिए गए कोड का उपयोग किया है, लेकिन यह कुछ भी करने के लिए प्रतीत नहीं होता है, मुझे क्या याद आ रही है?

using System;
using System.IO;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string illegal = "\"M<>\"\\a/ry/ h**ad:>> a\\/:*?\"<>| li*tt|le|| la\"mb.?";

            illegal = illegal.Trim(Path.GetInvalidFileNameChars());
            illegal = illegal.Trim(Path.GetInvalidPathChars());

            Console.WriteLine(illegal);
            Console.ReadLine();
        }
    }
}

1
ट्रिम स्ट्रिंग्स की शुरुआत और अंत से पात्रों को हटा देता है। हालाँकि, आपको संभवतः यह पूछना चाहिए कि डेटा अमान्य क्यों है, और इसके बजाय प्रयास करें और डेटा को ठीक / ठीक करें, डेटा को अस्वीकार करें।
user7116

8
यूनिक्स शैली के नाम विंडोज पर मान्य नहीं हैं और मैं 8.3 शॉर्टनेम से निपटना नहीं चाहता।
गैरी विल्बोबी

GetInvalidFileNameChars()फ़ोल्डर पथों से जैसे: \ आदि चीजों को पट्टी करेगा।
सीएडी

1
Path.GetInvalidPathChars()पट्टी करने के लिए प्रतीत नहीं होता है *या?
सीएडी

19
मैंने इस प्रश्न के पांच उत्तरों का परीक्षण किया (100,000 का समयबद्ध लूप) और निम्नलिखित विधि सबसे तेज़ है। नियमित अभिव्यक्ति ने 2 वां स्थान प्राप्त किया, और 25% धीमा था: सार्वजनिक स्ट्रिंग GetSafeFilename (स्ट्रिंग फ़ाइल नाम) {वापसी स्ट्रिंग। जॉइन ("_", फ़ाइल नाम ।plit (Path.GetInvalidFileenameChars ())); }
ब्रेन २२

जवाबों:


494

इसके बजाय कुछ इस तरह का प्रयास करें;

string illegal = "\"M\"\\a/ry/ h**ad:>> a\\/:*?\"| li*tt|le|| la\"mb.?";
string invalid = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());

foreach (char c in invalid)
{
    illegal = illegal.Replace(c.ToString(), ""); 
}

लेकिन मुझे टिप्पणियों से सहमत होना होगा, मैं शायद अवैध रास्तों के स्रोत से निपटने की कोशिश करूँगा, बजाय इसके कि किसी अवैध रास्ते को वैध बनाने का प्रयास किया जाए, लेकिन शायद अनपेक्षित रूप से।

संपादित करें: या एक संभावित 'बेहतर' समाधान, रेक्सक्स का उपयोग कर।

string illegal = "\"M\"\\a/ry/ h**ad:>> a\\/:*?\"| li*tt|le|| la\"mb.?";
string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch)));
illegal = r.Replace(illegal, "");

फिर भी, यह सवाल पूछा जाना चाहिए कि आप ऐसा क्यों कर रहे हैं।


40
दो सूचियों को एक साथ जोड़ना आवश्यक नहीं है। गैरकानूनी फ़ाइल नाम चार सूची में अवैध पथ चार सूची शामिल हैं और कुछ और हैं। यहां दोनों सूचियों की सूची डाली गई है: 34,60,62,124,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16, 17,18,19,20,21,22,23,24,25,26,28,28,29,30,31,58,42,63,92,47 34,60,62,124,0,1,2 , 3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27 , 28,29,30,31
सेरेल बोथा

9
@sjbotha यह Windows और Microsoft के .NET के कार्यान्वयन पर सही हो सकता है। मैं मोनो लिनक्स चलाने के लिए समान धारणा बनाने के लिए तैयार नहीं हूं।
मैथ्यू शारले

7
पहले उपाय के बारे में। एक स्ट्रिंग स्ट्रिंग से अधिक कुशल नहीं होना चाहिए?
एपिग्नोसिस

6
इसके लायक है, @MatthewScharley, GetInvalidPathChars () का मोनो कार्यान्वयन केवल 0x00 और GetInvalidFileNameChars () केवल 0x00 और '/' जब गैर-Windows प्लेटफ़ॉर्म पर चल रहा है। Windows पर, अमान्य वर्णों की सूची बहुत लंबी है, और GetInvalidPathChars () पूरी तरह से GetInvalidFileNameChars () के अंदर डुप्लिकेट है। यह देखने योग्य भविष्य में बदलने वाला नहीं है, इसलिए आप जो वास्तव में कर रहे हैं वह इस फ़ंक्शन को चलाने में लगने वाले समय को दोगुना कर रहा है क्योंकि आप चिंतित हैं कि वैध पथ की परिभाषा जल्द ही बदल जाएगी। जो यह नहीं होगा।
वॉरेन रुमक

13
@ चेरलेह यह चर्चा इतनी अनावश्यक है ... कोड को हमेशा अनुकूलित किया जाना चाहिए और इसके गलत होने का कोई जोखिम नहीं है। एक फ़ाइल नाम भी पथ का एक हिस्सा है। तो यह सिर्फ अतार्किक है GetInvalidPathChars()जिसमें ऐसे चरित्र शामिल हो सकते हैं जो GetInvalidFileNameChars()नहीं करेंगे। आप "समय से पहले" अनुकूलन पर शुद्धता नहीं ले रहे हैं। आप बस खराब कोड का उपयोग कर रहे हैं।
स्टीफन फेबियन

355

मूल प्रश्न "अवैध पात्रों को हटाने" के लिए कहा गया है:

public string RemoveInvalidChars(string filename)
{
    return string.Concat(filename.Split(Path.GetInvalidFileNameChars()));
}

इसके बजाय आप उन्हें बदलना चाह सकते हैं:

public string ReplaceInvalidChars(string filename)
{
    return string.Join("_", filename.Split(Path.GetInvalidFileNameChars()));    
}

यह जवाब सेरेस द्वारा एक और सूत्र पर था , मैं वास्तव में इसे साफ और सरल पसंद करता हूं।


10
ओपी के सवाल का सटीक जवाब देने के लिए, आपको "_" के बजाय "" का उपयोग करने की आवश्यकता होगी, लेकिन आपका उत्तर संभवतः व्यवहार में हम पर अधिक लागू होता है। मुझे लगता है कि कुछ कानूनी के साथ अवैध पात्रों को प्रतिस्थापित करना अधिक सामान्यतः किया जाता है।
BH

37
मैंने इस प्रश्न से पांच विधियों का परीक्षण किया (100,000 का समयबद्ध लूप) और यह विधि सबसे तेज़ है। नियमित अभिव्यक्ति ने 2 वां स्थान प्राप्त किया, और इस पद्धति की तुलना में 25% धीमा था।
ब्रेन २००

10
@BH की टिप्पणी को संबोधित करने के लिए, कोई केवल string.Concat (name.Split (Path.GetInvalidFileNameChars) ())
माइकल सटन

210

मैं फ़ाइलनाम को साफ करने के लिए लाइनक का उपयोग करता हूं। आप इसे आसानी से वैध रास्तों के लिए भी देख सकते हैं।

private static string CleanFileName(string fileName)
{
    return Path.GetInvalidFileNameChars().Aggregate(fileName, (current, c) => current.Replace(c.ToString(), string.Empty));
}

अपडेट करें

कुछ टिप्पणियां इंगित करती हैं कि यह विधि उनके लिए काम नहीं कर रही है, इसलिए मैंने एक डॉटनेटफीड स्निपेट के लिए एक लिंक शामिल किया है ताकि आप विधि को मान्य कर सकें।

https://dotnetfiddle.net/nw1SWY


4
इसने मेरे लिए काम नहीं किया। विधि स्वच्छ स्ट्रिंग वापस नहीं कर रही है। यह पारित फ़ाइल नाम के रूप में यह लौटा रहा है।
करण

@Karan ने क्या कहा, यह काम नहीं करता है, मूल स्ट्रिंग वापस आती है।
जॉन

आप वास्तव में Linq के साथ ऐसा कर सकते हैं, हालांकि var invalid = new HashSet<char>(Path.GetInvalidPathChars()); return new string(originalString.Where(s => !invalid.Contains(s)).ToArray()):। प्रदर्शन शायद महान नहीं है, लेकिन शायद इससे कोई फर्क नहीं पड़ता।
केसी

2
@ कर्ण या जॉन आप इस समारोह में क्या इनपुट भेज रहे हैं? इस विधि के सत्यापन के लिए मेरा संपादन देखें।
माइकल मिंटन

3
यह आसान है - लोग वैध चर के साथ तार गुजर रहे थे। कूल एग्रीगेट समाधान के लिए अपवोट किया गया।
निकोमीविच

89

आप इस तरह Linq का उपयोग करके अवैध वर्ण हटा सकते हैं:

var invalidChars = Path.GetInvalidFileNameChars();

var invalidCharsRemoved = stringWithInvalidChars
.Where(x => !invalidChars.Contains(x))
.ToArray();

संपादित करें
कि यह टिप्पणियों में उल्लिखित आवश्यक संपादन के साथ कैसा दिखता है:

var invalidChars = Path.GetInvalidFileNameChars();

string invalidCharsRemoved = new string(stringWithInvalidChars
  .Where(x => !invalidChars.Contains(x))
  .ToArray());

1
मुझे इस तरह से पसंद है: आप केवल स्ट्रिंग में अनुमत चार्ट रखते हैं (जो कि चार सरणी के अलावा और कुछ नहीं है)।
ड्यूड पास्कालो

6
मुझे पता है कि यह एक पुराना सवाल है, लेकिन यह एक भयानक जवाब है। हालाँकि, मैं यह जोड़ना चाहता था कि c # में आप char [] से स्ट्रिंग नहीं कर सकते हैं या तो स्पष्ट रूप से या स्पष्ट रूप से (पागल, मुझे पता है) इसलिए आपको इसे स्ट्रिंग निर्माता में छोड़ने की आवश्यकता होगी।
JNYRanger

1
मैंने इसकी पुष्टि नहीं की है, लेकिन मुझे उम्मीद है कि Path.GetInvalidPathChars () GetInvalidFileNameChars () का एक सुपरसेट हो सकता है और दोनों फ़ाइलनामों और रास्तों को कवर करने के लिए, इसलिए मैं इसके बजाय इसका उपयोग करूंगा।
कोणीयसेन

3
@anjdreas वास्तव में Path.GetInvalidPathChars () पथ का एक उपसमूह प्रतीत होता है। GetInvalidFileNameChars (), दूसरे तरीके से नहीं। उदाहरण के लिए Path.GetInvalidPathChars () वापस नहीं आएगा? '।
राफेल कोस्टा

1
यह एक अच्छा जवाब है। मैं फ़ाइल नाम सूची और फ़ाइलपथ सूची दोनों का उपयोग करता हूं: ____________________________ स्ट्रिंग क्लीनडाटा = नया स्ट्रिंग (data.Where! (X =>! Path.GetInvalidFileNameChars) ()। इसमें शामिल हैं (x &&! पथ। GetInvalidPathChars ())। toArray ());
goamn

27

ये सभी महान समाधान हैं, लेकिन वे सभी पर भरोसा करते हैं Path.GetInvalidFileNameChars, जो आपके विचार से उतना विश्वसनीय नहीं हो सकता है। MSDN प्रलेखन में निम्नलिखित टिप्पणी पर ध्यान दें Path.GetInvalidFileNameChars:

इस पद्धति से लौटाए गए सरणी में उन वर्णों का पूरा सेट शामिल करने की गारंटी नहीं है जो फ़ाइल और निर्देशिका नामों में अमान्य हैं। अमान्य वर्णों का पूरा सेट फ़ाइल सिस्टम द्वारा भिन्न हो सकता है। उदाहरण के लिए, Windows- आधारित डेस्कटॉप प्लेटफ़ॉर्म पर, अमान्य पथ वर्णों में ASCII / Unicode वर्ण 1 शामिल हो सकते हैं 31 के माध्यम से, साथ ही उद्धरण ("), से कम (<), से अधिक (>), पाइप (!), बैकस्पेस () \ b), null (\ 0) और टैब (\ t)।

यह Path.GetInvalidPathCharsविधि के साथ बेहतर नहीं है । इसमें ठीक वैसी ही टिप्पणी है।


13
तो फिर Path.GetInvalidFileNameChars का क्या मतलब है? मुझे उम्मीद है कि यह मौजूदा सिस्टम के लिए बिल्कुल अमान्य वर्णों को वापस करेगा, यह भरोसा करने के लिए .NET पर कि कौन सा फाइल सिस्टम मैं चल रहा हूं और मुझे फिटिंग अमान्य वर्ण प्रस्तुत कर रहा हूं। यदि यह मामला नहीं है और यह केवल हार्डकोड किए गए वर्ण लौटाता है, जो पहली जगह में विश्वसनीय नहीं हैं, तो इस विधि को हटा दिया जाना चाहिए क्योंकि इसमें शून्य मान है।
जनवरी

1
मुझे पता है कि यह एक पुरानी टिप्पणी है लेकिन, @ आप किसी अन्य फाइल सिस्टम पर लिखना चाह सकते हैं, शायद इसीलिए चेतावनी है।
fantastik78

3
@ fantastik78 अच्छा बिंदु, लेकिन इस मामले में मैं अपने दूरस्थ FS को निर्दिष्ट करने के लिए एक अतिरिक्त एनम तर्क रखना चाहता हूं। यदि यह बहुत अधिक रखरखाव का प्रयास है (जो कि सबसे अधिक संभावना है), तो यह पूरी विधि अभी भी एक बुरा विचार है, क्योंकि यह आपको सुरक्षा का गलत प्रभाव देता है।
Jan

1
@ जान मैं आपसे पूरी तरह सहमत हूँ, मैं सिर्फ चेतावनी के बारे में बहस कर रहा था।
fantastik78

दिलचस्प बात यह है कि यह एक तरह का "अमान्य सूची" है। यह "श्वेतसूची" केवल ज्ञात मान्य वर्ण "बेहतर" नहीं होगा? सफ़ेद अनुमति वाले ऐप के बजाय बेवकूफ "वायरसोकेनर" विचार की याद दिलाता है ....
बर्नहार्ड

26

फ़ाइल नामों के लिए:

var cleanFileName = string.Join("", fileName.Split(Path.GetInvalidFileNameChars()));

पूर्ण पथ के लिए:

var cleanPath = string.Join("", path.Split(Path.GetInvalidPathChars()));

ध्यान दें कि यदि आप इसे एक सुरक्षा सुविधा के रूप में उपयोग करने का इरादा रखते हैं, तो सभी पथों का विस्तार करने के लिए एक अधिक मजबूत दृष्टिकोण होगा और फिर यह सत्यापित करें कि उपयोगकर्ता द्वारा आपूर्ति की गई पथ वास्तव में एक निर्देशिका का बच्चा है जिसे उपयोगकर्ता तक पहुंच होनी चाहिए।


18

शुरुआत के लिए, ट्रिम केवल स्ट्रिंग की शुरुआत या अंत से पात्रों को निकालता है । दूसरे, आपको मूल्यांकन करना चाहिए कि क्या आप वास्तव में आपत्तिजनक पात्रों को हटाना चाहते हैं, या तेजी से विफल होते हैं और उपयोगकर्ता को पता है कि उनका फ़ाइल नाम अमान्य है। मेरी पसंद उत्तरार्द्ध है, लेकिन मेरा जवाब कम से कम आपको यह दिखाना चाहिए कि चीजों को सही और गलत तरीके से कैसे करना है:

StackOverflow प्रश्न दिखा रहा है कि कैसे जांचा जा सकता है कि दिया गया स्ट्रिंग एक मान्य फ़ाइल नाम है । ध्यान दें कि आप रेग्युलर एक्सप्रेशन रिप्लेसमेंट (यदि आपको वास्तव में ऐसा करने की आवश्यकता है) वाले पात्रों को हटाने के लिए इस प्रश्न से रेगेक्स का उपयोग कर सकते हैं।


मैं विशेष रूप से दूसरी सलाह से सहमत हूं।
ओरेगनगॉस्ट

4
मैं आम तौर पर दूसरे से सहमत होता हूं, लेकिन मेरे पास एक कार्यक्रम है जो एक फ़ाइल नाम बनाता है और जिसमें कुछ स्थितियों में अवैध चरित्र हो सकते हैं। चूँकि मेरा कार्यक्रम अवैध फ़ाइल नाम उत्पन्न कर रहा है, मुझे लगता है कि उन पात्रों को हटाना / बदलना उचित है। (बस एक वैध उपयोग के मामले की ओर इशारा करते हुए)
JDB अभी भी मोनिका

16

उपयोगकर्ता इनपुट से अवैध चरित्र को हटाने का सबसे अच्छा तरीका है Regex वर्ग का उपयोग करके अवैध चरित्र को बदलना, पीछे कोड में विधि बनाना या यह क्लाइंट पक्ष पर RegularExpression नियंत्रण का उपयोग करके भी मान्य करता है।

public string RemoveSpecialCharacters(string str)
{
    return Regex.Replace(str, "[^a-zA-Z0-9_]+", "_", RegexOptions.Compiled);
}

या

<asp:RegularExpressionValidator ID="regxFolderName" 
                                runat="server" 
                                ErrorMessage="Enter folder name with  a-z A-Z0-9_" 
                                ControlToValidate="txtFolderName" 
                                Display="Dynamic" 
                                ValidationExpression="^[a-zA-Z0-9_]*$" 
                                ForeColor="Red">

5
IMHO यह समाधान दूसरों की तुलना में बहुत बेहतर है बजाय सभी अमान्य वर्णों की खोज के जो केवल मान्य हैं।
--गुषी

15

मैं इसे प्राप्त करने के लिए नियमित अभिव्यक्ति का उपयोग करता हूं। सबसे पहले, मैं गतिशील रूप से रेगेक्स का निर्माण करता हूं।

string regex = string.Format(
                   "[{0}]",
                   Regex.Escape(new string(Path.GetInvalidFileNameChars())));
Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

तब मैं सिर्फ हटाने के लिए कॉल करता हूं InInvidChars.Replace खोज और प्रतिस्थापित करने के लिए। यह स्पष्ट रूप से और साथ ही पथ प्रभार को कवर करने के लिए बढ़ाया जा सकता है।


अजीब है, यह मेरे लिए काम कर रहा है। मौका मिलने पर मैं इसे दोबारा जांचूंगा। क्या आप अधिक विशिष्ट हो सकते हैं और समझा सकते हैं कि आपके लिए वास्तव में क्या काम नहीं कर रहा है?
जेफ़ येट्स

1
यह काम नहीं करेगा (ठीक से बहुत कम से कम) क्योंकि आप पथ पात्रों को ठीक से बच नहीं रहे हैं, और उनमें से कुछ का एक विशेष अर्थ है। ऐसा करने के लिए मेरे जवाब का संदर्भ लें।
मैथ्यू शार्ले

@ जेफ: आपका संस्करण अभी भी मैथ्यू से बेहतर है, अगर आप इसे थोड़ा संशोधित करते हैं। कैसे पर मेरे जवाब का संदर्भ लें।
Jan

2
मैं कुछ अन्य अमान्य फ़ाइल नाम पैटर्न भी new Regex(String.Format("^(CON|PRN|AUX|NUL|CLOCK\$|COM[1-9]|LPT[1-9])(?=\..|$)|(^(\.+|\s+)$)|((\.+|\s+)$)|([{0}])", Regex.Escape(new String(Path.GetInvalidFileNameChars()))), RegexOptions.Compiled | RegexOptions.Singleline | RegexOptions.CultureInvariant);
जोड़ूंगा

13

मैं बिल्कुल जेफ येट्स के विचार को पसंद करता हूं। यह पूरी तरह से काम करेगा, अगर आप इसे थोड़ा संशोधित करते हैं:

string regex = String.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars())));
Regex removeInvalidChars = new Regex(regex, RegexOptions.Singleline | RegexOptions.Compiled | RegexOptions.CultureInvariant);

सुधार केवल स्वचालित रूप से उत्पन्न रेगेक्स से बचने के लिए है।


11

यहां एक कोड स्निपेट है जो .NET 3 और उच्चतर के लिए मदद करना चाहिए।

using System.IO;
using System.Text.RegularExpressions;

public static class PathValidation
{
    private static string pathValidatorExpression = "^[^" + string.Join("", Array.ConvertAll(Path.GetInvalidPathChars(), x => Regex.Escape(x.ToString()))) + "]+$";
    private static Regex pathValidator = new Regex(pathValidatorExpression, RegexOptions.Compiled);

    private static string fileNameValidatorExpression = "^[^" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]+$";
    private static Regex fileNameValidator = new Regex(fileNameValidatorExpression, RegexOptions.Compiled);

    private static string pathCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidPathChars(), x => Regex.Escape(x.ToString()))) + "]";
    private static Regex pathCleaner = new Regex(pathCleanerExpression, RegexOptions.Compiled);

    private static string fileNameCleanerExpression = "[" + string.Join("", Array.ConvertAll(Path.GetInvalidFileNameChars(), x => Regex.Escape(x.ToString()))) + "]";
    private static Regex fileNameCleaner = new Regex(fileNameCleanerExpression, RegexOptions.Compiled);

    public static bool ValidatePath(string path)
    {
        return pathValidator.IsMatch(path);
    }

    public static bool ValidateFileName(string fileName)
    {
        return fileNameValidator.IsMatch(fileName);
    }

    public static string CleanPath(string path)
    {
        return pathCleaner.Replace(path, "");
    }

    public static string CleanFileName(string fileName)
    {
        return fileNameCleaner.Replace(fileName, "");
    }
}

8

ऊपर दिए गए अधिकांश समाधान पथ और फ़ाइल नाम दोनों के लिए अवैध वर्णों को जोड़ते हैं जो कि गलत है (यहां तक ​​कि जब दोनों कॉल वर्तमान में वर्णों का एक ही सेट लौटाते हैं)। मैं पहले पथ + फ़ाइलनाम को पथ और फ़ाइल नाम में विभाजित करूँगा, फिर उपयुक्त सेट को या तो उन्हें लागू करूँगा और फिर दोनों को फिर से संयोजित करूँगा।

wvd_vegt


+1: बहुत सही है। आज .NET 4.0 में काम करते हुए, शीर्ष उत्तर से रेगेक्स समाधान ने सभी बैकस्लैशों को पूर्ण पथ में ले लिया। इसलिए मैंने dir पथ के लिए एक regex और सिर्फ फ़ाइल नाम के लिए एक regex बनाया, अलग से साफ किया और पुन: संयोजित किया
dario_ramos

यह सच हो सकता है लेकिन इस सवाल का जवाब नहीं है। मुझे यकीन नहीं है कि एक अस्पष्ट 'मैं इसे इस तरह करूंगा' यहां पहले से मौजूद कुछ संपूर्ण समाधानों की तुलना में बहुत मददगार है (उदाहरण के लिए लिली का जवाब, नीचे देखें)
इयान ग्रेिंगर

6

यदि आप किसी एकल वर्ण को अमान्य वर्णों से निकालते हैं या प्रतिस्थापित करते हैं, तो आपके पास टकराव हो सकते हैं:

<abc -> abc
>abc -> abc

इससे बचने के लिए यहां एक सरल विधि दी गई है:

public static string ReplaceInvalidFileNameChars(string s)
{
    char[] invalidFileNameChars = System.IO.Path.GetInvalidFileNameChars();
    foreach (char c in invalidFileNameChars)
        s = s.Replace(c.ToString(), "[" + Array.IndexOf(invalidFileNameChars, c) + "]");
    return s;
}

परिणाम:

 <abc -> [1]abc
 >abc -> [2]abc

5

एक अपवाद फेंक दें।

if ( fileName.IndexOfAny(Path.GetInvalidFileNameChars()) > -1 )
            {
                throw new ArgumentException();
            }

4

मैंने इस राक्षस को मज़े के लिए लिखा है, यह आपको गोल करने की सुविधा देता है:

public static class FileUtility
{
    private const char PrefixChar = '%';
    private static readonly int MaxLength;
    private static readonly Dictionary<char,char[]> Illegals;
    static FileUtility()
    {
        List<char> illegal = new List<char> { PrefixChar };
        illegal.AddRange(Path.GetInvalidFileNameChars());
        MaxLength = illegal.Select(x => ((int)x).ToString().Length).Max();
        Illegals = illegal.ToDictionary(x => x, x => ((int)x).ToString("D" + MaxLength).ToCharArray());
    }

    public static string FilenameEncode(string s)
    {
        var builder = new StringBuilder();
        char[] replacement;
        using (var reader = new StringReader(s))
        {
            while (true)
            {
                int read = reader.Read();
                if (read == -1)
                    break;
                char c = (char)read;
                if(Illegals.TryGetValue(c,out replacement))
                {
                    builder.Append(PrefixChar);
                    builder.Append(replacement);
                }
                else
                {
                    builder.Append(c);
                }
            }
        }
        return builder.ToString();
    }

    public static string FilenameDecode(string s)
    {
        var builder = new StringBuilder();
        char[] buffer = new char[MaxLength];
        using (var reader = new StringReader(s))
        {
            while (true)
            {
                int read = reader.Read();
                if (read == -1)
                    break;
                char c = (char)read;
                if (c == PrefixChar)
                {
                    reader.Read(buffer, 0, MaxLength);
                    var encoded =(char) ParseCharArray(buffer);
                    builder.Append(encoded);
                }
                else
                {
                    builder.Append(c);
                }
            }
        }
        return builder.ToString();
    }

    public static int ParseCharArray(char[] buffer)
    {
        int result = 0;
        foreach (char t in buffer)
        {
            int digit = t - '0';
            if ((digit < 0) || (digit > 9))
            {
                throw new ArgumentException("Input string was not in the correct format");
            }
            result *= 10;
            result += digit;
        }
        return result;
    }
}

1
मुझे यह पसंद है क्योंकि यह एक ही परिणामी पथ बनाने वाले दो अलग-अलग तारों से बचा जाता है।
किम

3

मुझे लगता है कि रेगेक्स का उपयोग करके इसे सत्यापित करना बहुत आसान है और सभी खराब पात्रों की जांच करने के बजाय, कौन से पात्रों को अनुमति दी जाती है। ये लिंक देखें: http://www.c-sharpcorner.com/UploadFile/prasad_1/RegExpPSD12062005021717AM/RegExpPSD.aspx http://www.windowsdevcenter.com/pub/a/oreilly/windows/news/csharp_0101.html

इसके अलावा, "नियमित अभिव्यक्ति संपादक" के लिए एक खोज करें, वे बहुत मदद करते हैं। कुछ ऐसे भी हैं जो आपके लिए c # में भी कोड आउटपुट करते हैं।


यह देखते हुए कि .net एक ऐसा ढांचा है, जिसका उद्देश्य कई प्लेटफार्मों (जैसे लिनक्स / यूनिक्स के साथ-साथ विंडोज़) पर प्रोग्राम चलाने की अनुमति देना है, मुझे लगता है कि Path.GetInvalidFileNameChars () सबसे अच्छा है क्योंकि इसमें क्या है या isn 'का ज्ञान होगा। आपके प्रोग्राम पर चल रहे फाइल सिस्टम पर मान्य नहीं है। यहां तक ​​कि अगर आपका प्रोग्राम लिनक्स पर कभी नहीं चलेगा (शायद यह WPF कोड से भरा है), तो हमेशा मौका होता है कि भविष्य में कुछ नए विंडोज फाइल सिस्टम साथ आएंगे और अलग-अलग वैध / अमान्य वर्ण होंगे। रेगेक्स के साथ अपना खुद का रोल करना पहिया को फिर से मजबूत कर रहा है, और एक प्लेटफ़ॉर्म मुद्दे को अपने कोड में स्थानांतरित कर रहा है।
डैनियल स्कॉट

मैं हालांकि ऑनलाइन regex संपादकों / परीक्षकों पर आपकी सलाह से सहमत हूं। मुझे वे अमूल्य लगते हैं (क्योंकि रेगीज़ ट्रिकी चीजें हैं, और सूक्ष्मता से भरपूर है जो आपको आसानी से यात्रा कर सकती है, जिससे आपको एक एग्जॉस्ट मिल जाता है जो कि किनारे के मामलों के साथ कुछ बेतहाशा अप्रत्याशित तरीके से व्यवहार करता है)। मेरा पसंदीदा regex101.com है (मुझे यह पसंद है कि यह कैसे regex को तोड़ता है और आपको स्पष्ट रूप से दिखाता है कि यह क्या अपेक्षा रखता है )। मुझे भी debuggex.com काफी पसंद है क्योंकि इसमें मैच समूहों और चरित्र वर्गों और व्हाट्सएप का एक कॉम्पैक्ट दृश्य प्रतिनिधित्व मिला है।
डैनियल स्कॉट

3

यह O (n) प्रतीत होता है और स्ट्रिंग्स पर बहुत अधिक मेमोरी खर्च नहीं करता है:

    private static readonly HashSet<char> invalidFileNameChars = new HashSet<char>(Path.GetInvalidFileNameChars());

    public static string RemoveInvalidFileNameChars(string name)
    {
        if (!name.Any(c => invalidFileNameChars.Contains(c))) {
            return name;
        }

        return new string(name.Where(c => !invalidFileNameChars.Contains(c)).ToArray());
    }

1
जब आप 'कोई' फ़ंक्शन का उपयोग करते हैं तो मुझे नहीं लगता कि यह O (n) है।
II ARROWS

@IIARROWS और आपकी राय में यह क्या है?
एलेक्सी एफ

मुझे नहीं पता, यह ऐसा महसूस नहीं हुआ जब मैंने अपनी टिप्पणी लिखी थी ... अब जब मैंने इसकी गणना करने की कोशिश की, तो लगता है कि आप सही हैं।
II ARROWS

आपके प्रदर्शन पर विचार करने के कारण मैंने इसे चुना है। धन्यवाद।
बेरेंड एन्गेलब्रैच

3

यहां जवाबों पर स्कैन करते हुए, वे सभी ** अमान्य फ़ाइल नाम वर्णों के एक चार सरणी का उपयोग करना शामिल करते हैं।

दी, यह सूक्ष्म-अनुकूलन हो सकता है - लेकिन किसी के लाभ के लिए जो वैध फ़ाइल नाम होने के लिए बड़ी संख्या में मानों की जांच करना चाह रहे हैं, यह ध्यान देने योग्य है कि अमान्य वर्णों के हैशसेट के निर्माण से उल्लेखनीय रूप से बेहतर प्रदर्शन होगा।

मैं अतीत में बहुत हैरान (हैरान) हुआ हूं कि किसी सूची से अधिक जल्दी से हैशसेट (या शब्दकोश) आउटपरफॉर्म कैसे होता है। स्ट्रिंग्स के साथ, यह एक हास्यास्पद कम संख्या (स्मृति से लगभग 5-7 आइटम) है। अधिकांश अन्य सरल डेटा (ऑब्जेक्ट संदर्भ, संख्या आदि) के साथ जादू क्रॉसओवर लगभग 20 आइटम लगता है।

Path.InvalidFileNameChars "सूची" में 40 अमान्य वर्ण हैं। आज एक खोज की और स्टैकऑवरफ्लो पर यहाँ एक बहुत अच्छा बेंचमार्क है जो हैशसेट दिखाता है कि किसी ऐरे / सूची के आधे समय में 40 वस्तुओं के लिए थोड़ा अधिक समय लगेगा: https://stackoverflow.com/a/10762995/9494179

यहाँ पथ प्रदर्शक के लिए मैं सहायक श्रेणी का उपयोग करता हूँ। मैं अब भूल गया कि मेरे पास इसमें फैंसी प्रतिस्थापन विकल्प क्यों था, लेकिन यह एक प्यारा बोनस के रूप में है।

अतिरिक्त बोनस विधि "IsValidLocalPath" भी :)

(** जो लोग नियमित अभिव्यक्ति का उपयोग नहीं करते हैं)

public static class PathExtensions
{
    private static HashSet<char> _invalidFilenameChars;
    private static HashSet<char> InvalidFilenameChars
    {
        get { return _invalidFilenameChars ?? (_invalidFilenameChars = new HashSet<char>(Path.GetInvalidFileNameChars())); }
    }


    /// <summary>Replaces characters in <c>text</c> that are not allowed in file names with the 
    /// specified replacement character.</summary>
    /// <param name="text">Text to make into a valid filename. The same string is returned if 
    /// it is valid already.</param>
    /// <param name="replacement">Replacement character, or NULL to remove bad characters.</param>
    /// <param name="fancyReplacements">TRUE to replace quotes and slashes with the non-ASCII characters ” and ⁄.</param>
    /// <returns>A string that can be used as a filename. If the output string would otherwise be empty, "_" is returned.</returns>
    public static string ToValidFilename(this string text, char? replacement = '_', bool fancyReplacements = false)
    {
        StringBuilder sb = new StringBuilder(text.Length);
        HashSet<char> invalids = InvalidFilenameChars;
        bool changed = false;

        for (int i = 0; i < text.Length; i++)
        {
            char c = text[i];
            if (invalids.Contains(c))
            {
                changed = true;
                char repl = replacement ?? '\0';
                if (fancyReplacements)
                {
                    if (c == '"') repl = '”'; // U+201D right double quotation mark
                    else if (c == '\'') repl = '’'; // U+2019 right single quotation mark
                    else if (c == '/') repl = '⁄'; // U+2044 fraction slash
                }
                if (repl != '\0')
                    sb.Append(repl);
            }
            else
                sb.Append(c);
        }

        if (sb.Length == 0)
            return "_";

        return changed ? sb.ToString() : text;
    }


    /// <summary>
    /// Returns TRUE if the specified path is a valid, local filesystem path.
    /// </summary>
    /// <param name="pathString"></param>
    /// <returns></returns>
    public static bool IsValidLocalPath(this string pathString)
    {
        // From solution at https://stackoverflow.com/a/11636052/949129
        Uri pathUri;
        Boolean isValidUri = Uri.TryCreate(pathString, UriKind.Absolute, out pathUri);
        return isValidUri && pathUri != null && pathUri.IsLoopback;
    }
}

2
public static class StringExtensions
      {
        public static string RemoveUnnecessary(this string source)
        {
            string result = string.Empty;
            string regex = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
            Regex reg = new Regex(string.Format("[{0}]", Regex.Escape(regex)));
            result = reg.Replace(source, "");
            return result;
        }
    }

आप स्पष्ट रूप से विधि का उपयोग कर सकते हैं।


2

फ़ाइल नाम में वर्ण Path.GetInvalidPathChars(), +और #प्रतीक और अन्य विशिष्ट नाम नहीं हो सकते । हमने सभी जांचों को एक वर्ग में जोड़ा:

public static class FileNameExtensions
{
    private static readonly Lazy<string[]> InvalidFileNameChars =
        new Lazy<string[]>(() => Path.GetInvalidPathChars()
            .Union(Path.GetInvalidFileNameChars()
            .Union(new[] { '+', '#' })).Select(c => c.ToString(CultureInfo.InvariantCulture)).ToArray());


    private static readonly HashSet<string> ProhibitedNames = new HashSet<string>
    {
        @"aux",
        @"con",
        @"clock$",
        @"nul",
        @"prn",

        @"com1",
        @"com2",
        @"com3",
        @"com4",
        @"com5",
        @"com6",
        @"com7",
        @"com8",
        @"com9",

        @"lpt1",
        @"lpt2",
        @"lpt3",
        @"lpt4",
        @"lpt5",
        @"lpt6",
        @"lpt7",
        @"lpt8",
        @"lpt9"
    };

    public static bool IsValidFileName(string fileName)
    {
        return !string.IsNullOrWhiteSpace(fileName)
            && fileName.All(o => !IsInvalidFileNameChar(o))
            && !IsProhibitedName(fileName);
    }

    public static bool IsProhibitedName(string fileName)
    {
        return ProhibitedNames.Contains(fileName.ToLower(CultureInfo.InvariantCulture));
    }

    private static string ReplaceInvalidFileNameSymbols([CanBeNull] this string value, string replacementValue)
    {
        if (value == null)
        {
            return null;
        }

        return InvalidFileNameChars.Value.Aggregate(new StringBuilder(value),
            (sb, currentChar) => sb.Replace(currentChar, replacementValue)).ToString();
    }

    public static bool IsInvalidFileNameChar(char value)
    {
        return InvalidFileNameChars.Value.Contains(value.ToString(CultureInfo.InvariantCulture));
    }

    public static string GetValidFileName([NotNull] this string value)
    {
        return GetValidFileName(value, @"_");
    }

    public static string GetValidFileName([NotNull] this string value, string replacementValue)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            throw new ArgumentException(@"value should be non empty", nameof(value));
        }

        if (IsProhibitedName(value))
        {
            return (string.IsNullOrWhiteSpace(replacementValue) ? @"_" : replacementValue) + value; 
        }

        return ReplaceInvalidFileNameSymbols(value, replacementValue);
    }

    public static string GetFileNameError(string fileName)
    {
        if (string.IsNullOrWhiteSpace(fileName))
        {
            return CommonResources.SelectReportNameError;
        }

        if (IsProhibitedName(fileName))
        {
            return CommonResources.FileNameIsProhibited;
        }

        var invalidChars = fileName.Where(IsInvalidFileNameChar).Distinct().ToArray();

        if(invalidChars.Length > 0)
        {
            return string.Format(CultureInfo.CurrentCulture,
                invalidChars.Length == 1 ? CommonResources.InvalidCharacter : CommonResources.InvalidCharacters,
                StringExtensions.JoinQuoted(@",", @"'", invalidChars.Select(c => c.ToString(CultureInfo.CurrentCulture))));
        }

        return string.Empty;
    }
}

विधि GetValidFileNameसभी गलत डेटा को बदल देती है _


2

Windows फ़ाइल नामकरण के लिए किसी भी अवैध चार्ट से स्ट्रिंग को साफ करने के लिए एक लाइनर:

public static string CleanIllegalName(string p_testName) => new Regex(string.Format("[{0}]", Regex.Escape(new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars())))).Replace(p_testName, "");

1
public static bool IsValidFilename(string testName)
{
    return !new Regex("[" + Regex.Escape(new String(System.IO.Path.GetInvalidFileNameChars())) + "]").IsMatch(testName);
}

0

यह आप चाहते हैं कि आप चाहते हैं, और टकराव से बचना होगा

 static string SanitiseFilename(string key)
    {
        var invalidChars = Path.GetInvalidFileNameChars();
        var sb = new StringBuilder();
        foreach (var c in key)
        {
            var invalidCharIndex = -1;
            for (var i = 0; i < invalidChars.Length; i++)
            {
                if (c == invalidChars[i])
                {
                    invalidCharIndex = i;
                }
            }
            if (invalidCharIndex > -1)
            {
                sb.Append("_").Append(invalidCharIndex);
                continue;
            }

            if (c == '_')
            {
                sb.Append("__");
                continue;
            }

            sb.Append(c);
        }
        return sb.ToString();

    }

0

मुझे लगता है कि प्रश्न पहले से ही पूर्ण उत्तर नहीं दिया गया है ... उत्तर केवल स्वच्छ फ़ाइलनाम या पथ का वर्णन करते हैं ... दोनों नहीं। यहाँ मेरा समाधान है:

private static string CleanPath(string path)
{
    string regexSearch = new string(Path.GetInvalidFileNameChars()) + new string(Path.GetInvalidPathChars());
    Regex r = new Regex(string.Format("[{0}]", Regex.Escape(regexSearch)));
    List<string> split = path.Split('\\').ToList();
    string returnValue = split.Aggregate(string.Empty, (current, s) => current + (r.Replace(s, "") + @"\"));
    returnValue = returnValue.TrimEnd('\\');
    return returnValue;
}

0

मैंने एक एक्सटेंशन विधि बनाई जो कई सुझावों को जोड़ती है:

  1. हैश सेट में अवैध पात्रों को पकड़ना
  2. Ascii 127 के नीचे के वर्णों को छानना। चूंकि Path.GetInvalidFileNameChars में 0 से 255 तक के साथ सभी अवैध वर्ण संभव नहीं हैं। यहाँ और MSDN देखें
  3. प्रतिस्थापन चरित्र को परिभाषित करने की संभावना

स्रोत:

public static class FileNameCorrector
{
    private static HashSet<char> invalid = new HashSet<char>(Path.GetInvalidFileNameChars());

    public static string ToValidFileName(this string name, char replacement = '\0')
    {
        var builder = new StringBuilder();
        foreach (var cur in name)
        {
            if (cur > 31 && cur < 128 && !invalid.Contains(cur))
            {
                builder.Append(cur);
            }
            else if (replacement != '\0')
            {
                builder.Append(replacement);
            }
        }

        return builder.ToString();
    }
}

0

यहाँ एक फ़ंक्शन है जो एक प्रतिस्थापन नाम से सभी अवैध पात्रों को फ़ाइल नाम में बदल देता है:

public static string ReplaceIllegalFileChars(string FileNameWithoutPath, char ReplacementChar)
{
  const string IllegalFileChars = "*?/\\:<>|\"";
  StringBuilder sb = new StringBuilder(FileNameWithoutPath.Length);
  char c;

  for (int i = 0; i < FileNameWithoutPath.Length; i++)
  {
    c = FileNameWithoutPath[i];
    if (IllegalFileChars.IndexOf(c) >= 0)
    {
      c = ReplacementChar;
    }
    sb.Append(c);
  }
  return (sb.ToString());
}

उदाहरण के लिए अंडरस्कोर को रिप्लेसमेंट कैरेक्टर के रूप में इस्तेमाल किया जा सकता है:

NewFileName = ReplaceIllegalFileChars(FileName, '_');

आपके द्वारा प्रदान किए गए उत्तर के अलावा, कृपया इस बात की संक्षिप्त व्याख्या प्रदान करें कि यह समस्या क्यों और कैसे ठीक होती है।
jtate

-7

या आप बस कर सकते हैं

[YOUR STRING].Replace('\\', ' ').Replace('/', ' ').Replace('"', ' ').Replace('*', ' ').Replace(':', ' ').Replace('?', ' ').Replace('<', ' ').Replace('>', ' ').Replace('|', ' ').Trim();
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.