Windows RENAME कमांड वाइल्डकार्ड की व्याख्या कैसे करती है?


77

Windows RENAME (REN) कमांड वाइल्डकार्ड की व्याख्या कैसे करती है?

एचईएलपी सुविधा में निर्मित कोई मदद नहीं है - यह वाइल्डकार्ड को बिल्कुल भी संबोधित नहीं करता है।

माइक्रोसॉफ्ट TechNet XP ऑनलाइन मदद बहुत बेहतर नहीं है। यहाँ वाइल्डकार्ड के बारे में कहना है:

"आप वाइल्डकार्ड ( *और ?) या तो फ़ाइल नाम पैरामीटर में उपयोग कर सकते हैं । यदि आप फ़ाइलनाम 2 में वाइल्डकार्ड का उपयोग करते हैं, तो वाइल्डकार्ड द्वारा दर्शाए गए वर्ण फ़ाइलनाम 1 के संबंधित वर्णों के समान होंगे।"

ज्यादा मदद नहीं - ऐसे कई तरीके हैं जिनसे बयान की व्याख्या की जा सकती है।

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

अगर मुझे पता है कि वाइल्डकार्ड कैसे संसाधित किए जाते हैं, तो मुझे पता है कि मैं RENAME कमांड का उपयोग अधिक प्रभावी ढंग से कर सकता हूं, बिना अक्सर बैच के लिए। बेशक नियमों को जानने से बैच विकास को भी लाभ होगा।

(हां - यह एक ऐसा मामला है जहां मैं एक युग्मित प्रश्न और उत्तर पोस्ट कर रहा हूं। मैं नियमों को न जानने के कारण थक गया और अपने दम पर प्रयोग करने का फैसला किया। मुझे लगता है कि मैंने जो खोजा है, उसमें कई अन्य लोग रुचि ले सकते हैं)


यहाँ वाइल्डकार्ड के साथ नाम बदलने के अच्छे उदाहरणों के ढेर हैं: lagmonster.org/docs/DOS7/z-ren1.html
मैथ्यू लॉक

5
@MatthewLock - दिलचस्प लिंक, लेकिन वे नियम और उदाहरण MSDOS 7 के लिए हैं, विंडोज के लिए नहीं । महत्वपूर्ण अंतर हैं। उदाहरण के लिए, MSDOS *विंडोज के बाद अतिरिक्त वर्णों को लागू करने की अनुमति नहीं देता है। जिसके बहुत बड़े परिणाम हैं। काश मुझे उस साइट के बारे में पता होता; हो सकता है कि इससे मेरी जाँच आसान हो गई हो। MSDOS7 के नियम काफी भिन्न हैं तो पुराने DOS लंबे फ़ाइल नामों से पहले नियम करते हैं, और वे इस दिशा में एक कदम है कि इसे कैसे संभालते हैं। मुझे पूर्व लंबी फ़ाइल का नाम डॉस नियम मिला था, और वे मेरी जांच के लिए बेकार थे।
denham

मुझे यह पता नहीं था;)
मैथ्यू लॉक

जवाबों:


116

विस्टा मशीन पर व्यापक परीक्षण के बाद इन नियमों की खोज की गई थी। फ़ाइल नामों में यूनिकोड के साथ कोई परीक्षण नहीं किया गया था।

RENAME को 2 मापदंडों की आवश्यकता होती है - एक sourceMask, उसके बाद targetMask। SourceMask और targetMask दोनों में *और / या ?वाइल्डकार्ड शामिल हो सकते हैं । वाइल्डकार्ड का व्यवहार स्रोत और लक्ष्य मास्क के बीच थोड़ा बदलता है।

नोट - REN का उपयोग किसी फ़ोल्डर का नाम बदलने के लिए किया जा सकता है, लेकिन वाइल्डकार्ड को किसी फ़ोल्डर का नाम बदलने के दौरान sourceMask या targetMask में अनुमति नहीं है । यदि SourceMask कम से कम एक फ़ाइल से मेल खाता है, तो फ़ाइल का नाम बदल दिया जाएगा और फ़ोल्डर्स को अनदेखा कर दिया जाएगा। यदि SourceMask केवल फ़ोल्डर और फ़ाइलों से मेल खाती है, तो वाइल्डकार्ड स्रोत या लक्ष्य में दिखाई देने पर एक सिंटैक्स त्रुटि उत्पन्न होती है। यदि SourceMask कुछ भी मेल नहीं खाता है, तो "फ़ाइल नहीं मिली" त्रुटि परिणाम।

फ़ाइलों का नाम बदलने के दौरान, वाइल्डकार्ड को केवल स्रोत नाम के फ़ाइल नाम भाग में अनुमति दी जाती है। फ़ाइल नाम तक जाने वाले मार्ग में वाइल्डकार्ड की अनुमति नहीं है।

sourceMask

SourceMask यह निर्धारित करने के लिए फ़िल्टर के रूप में काम करता है कि कौन सी फ़ाइलों का नाम बदला गया है। वाइल्डकार्ड यहाँ किसी भी अन्य कमांड के साथ काम करते हैं जो फ़ाइल नामों को फ़िल्टर करते हैं।

  • ?- इस वाइल्डकार्ड को छोड़कर किसी भी 0 या 1 वर्ण से मेल खाता .है - यह हमेशा लालची होता है, अगर यह नाम नहीं है तो यह अगले वर्ण का उपभोग करता है, अगर यह . नाम के अंत में या बिना असफलता के कुछ भी मेल नहीं खाता है, तो अगला चरित्र a है.

  • *- किसी भी 0 या अधिक वर्ण मेल सहित . (नीचे एक अपवाद के साथ)। यह वाइल्डकार्ड लालची नहीं है। यह बाद के पात्रों को मैच करने में सक्षम करने के लिए जितना संभव हो उतना कम या उतना ही मेल खाएगा।

सभी गैर-वाइल्डकार्ड वर्ण खुद को कुछ विशेष केस अपवादों के साथ मेल खाना चाहिए।

  • .- खुद से मेल खाता है या यह नाम के अंत (कुछ भी नहीं) से मेल कर सकता है अगर कोई और चरित्र नहीं रहता है। (नोट - एक वैध विंडोज नाम के साथ समाप्त नहीं हो सकता .)

  • {space}- खुद से मेल खाता है या यह नाम के अंत (कुछ भी नहीं) से मेल कर सकता है अगर कोई और चरित्र नहीं रहता है। (नोट - एक वैध विंडोज नाम के साथ समाप्त नहीं हो सकता {space})

  • *.अंत में - किसी भी 0 या अधिक वर्ण से मेल खाता है , समाप्त करने के अलावा वास्तव में किसी भी संयोजन हो सकता है और जब तक मुखौटा में बहुत अंतिम चरित्र है यह केवल और केवल अपवाद है जहां केवल वर्णों के किसी भी सेट से मेल नहीं खाता है।...{space}.*

उपरोक्त नियम उस जटिल नहीं हैं। लेकिन एक और बहुत महत्वपूर्ण नियम है जो स्थिति को भ्रामक बनाता है: SourceMask की तुलना लंबे नाम और लघु 8.3 नाम (यदि यह मौजूद है) से की जाती है। यह अंतिम नियम परिणामों की व्याख्या को बहुत मुश्किल बना सकता है, क्योंकि यह हमेशा स्पष्ट नहीं होता है जब मुखौटा संक्षिप्त नाम के माध्यम से मेल खाता है।

NTFS वॉल्यूम पर लघु 8.3 नामों की पीढ़ी को अक्षम करने के लिए RegEdit का उपयोग करना संभव है, जिस बिंदु पर फ़ाइल मास्क परिणामों की व्याख्या अधिक सीधे होती है। कोई भी संक्षिप्त नाम जो संक्षिप्त नामों को अक्षम करने से पहले उत्पन्न किया गया था।

targetMask

नोट - मैंने कोई कठोर परीक्षण नहीं किया है, लेकिन ऐसा प्रतीत होता है कि ये वही नियम COPY कमैंड के लक्षित नाम के लिए भी काम करते हैं

लक्ष्यमास्क नए नाम को निर्दिष्ट करता है। इसे हमेशा पूर्ण लंबे नाम पर लागू किया जाता है; टारगेटमास्क को कभी भी छोटे 8.3 नाम पर लागू नहीं किया जाता है, भले ही sourceMask लघु 8.3 नाम से मेल खाता हो।

SourceMask में वाइल्डकार्ड की मौजूदगी या अनुपस्थिति का कोई असर नहीं पड़ता है कि टारगेट मास्क में वाइल्डकार्ड कैसे संसाधित होते हैं।

निम्नलिखित चर्चा में - cकिसी भी चरित्र का प्रतिनिधित्व करता है *, जो नहीं है ?, या.

टारगेटमास्क को स्रोत के नाम के विरुद्ध संसाधित किया जाता है, जो बाएं से दाएं बिना बैक-ट्रैकिंग के कड़ाई से होता है।

  • c- स्रोत नाम के भीतर स्थिति को तब तक आगे .बढ़ाया जाता है जब तक कि अगला चरित्र नहीं है और cलक्ष्य नाम के साथ जुड़ जाता है। (उस वर्ण को cप्रतिस्थापित करता है जो स्रोत में था , लेकिन कभी प्रतिस्थापित नहीं होता .)

  • ?- स्रोत के अगले नाम से अगले वर्ण का मिलान करता है और इसे लक्षित नाम तक जोड़ता है जब तक कि अगला वर्ण नहीं है . यदि अगला वर्ण है .या यदि स्रोत नाम के अंत में है तो परिणाम और वर्तमान में कोई वर्ण नहीं जोड़ा जाता है स्रोत नाम के भीतर स्थिति अपरिवर्तित है।

  • *targetMask के अंत में - स्रोत से शेष सभी वर्णों को लक्ष्य पर लागू करता है। यदि पहले से ही स्रोत के अंत में है, तो कुछ भी नहीं करता है।

  • *c- c(स्थिति के प्रति संवेदनशील लालची मैच) के अंतिम समय के माध्यम से वर्तमान स्थिति से सभी स्रोत वर्णों को जोड़ता है और वर्णों के मिलान सेट को लक्ष्य नाम में जोड़ता है। यदि cनहीं मिला है, तो स्रोत से सभी शेष वर्णों को जोड़ा जाता है, इसके बाद c यह एकमात्र ऐसी स्थिति है जिसके बारे में मुझे पता है कि विंडोज फ़ाइल पैटर्न मिलान कहाँ संवेदनशील है।

  • *.- (लालची मैच) के अंतिम भटकाव के माध्यम से वर्तमान स्थिति से सभी स्रोत वर्णों को .जोड़ता है और वर्णों के मिलान सेट को लक्ष्य नाम में जोड़ता है। यदि .नहीं मिला है, तो स्रोत से सभी शेष वर्ण जोड़े जाते हैं, उसके बाद.

  • *?- शेष सभी वर्णों को स्रोत से लक्ष्य तक जोड़ता है। यदि पहले से ही स्रोत के अंत में है तो कुछ भी नहीं करता है।

  • .*सामने के बिना - किसी भी वर्ण की नकल के बिना पहले स्थिति के माध्यम से स्रोत में स्थिति को आगे बढ़ाता है ., और .लक्ष्य नाम के लिए संलग्न करता है। यदि .स्रोत में नहीं मिला है, तो स्रोत के अंत तक आगे बढ़ता .है और लक्ष्य नाम के लिए अपील करता है।

लक्ष्यमास्क समाप्त हो जाने के बाद, कोई भी अनुगामी .और {space}परिणामी लक्ष्य नाम के अंत से छंटनी की जाती है क्योंकि Windows फ़ाइल नाम .या तो समाप्त हो सकते हैं{space}

कुछ व्यावहारिक उदाहरण

किसी भी एक्सटेंशन से पहले और तीसरे स्थान पर एक चरित्र को प्रतिस्थापित करें (यदि यह अभी तक मौजूद नहीं है तो दूसरा या तीसरा वर्ण जोड़ता है)

ren  *  A?Z*
  1        -> AZ
  12       -> A2Z
  1.txt    -> AZ.txt
  12.txt   -> A2Z.txt
  123      -> A2Z
  123.txt  -> A2Z.txt
  1234     -> A2Z4
  1234.txt -> A2Z4.txt

हर फाइल का अंतिम (फाइनल) एक्सटेंशन बदलें

ren  *  *.txt
  a     -> a.txt
  b.dat -> b.txt
  c.x.y -> c.x.txt

हर फ़ाइल के लिए एक एक्सटेंशन जोड़ें

ren  *  *?.bak
  a     -> a.bak
  b.dat -> b.dat.bak
  c.x.y -> c.x.y.bak

प्रारंभिक विस्तार के बाद कोई अतिरिक्त एक्सटेंशन निकालें। ध्यान दें कि ?पूर्ण मौजूदा नाम और प्रारंभिक एक्सटेंशन को संरक्षित करने के लिए पर्याप्त उपयोग किया जाना चाहिए।

ren  *  ?????.?????
  a     -> a
  a.b   -> a.b
  a.b.c -> a.b
  part1.part2.part3    -> part1.part2
  123456.123456.123456 -> 12345.12345   (note truncated name and extension because not enough `?` were used)

ऊपर के समान, लेकिन प्रारंभिक नाम और / या 5 वर्णों से अधिक समय तक फ़ाइलों को फ़िल्टर करें ताकि वे छंटनी न हों। (स्पष्ट रूप ?से लक्ष्य के अंतिम छोर पर अतिरिक्त जोड़ सकते हैं 6 नाम तक के नाम और एक्सटेंशन संरक्षित करने के लिए)

ren  ?????.?????.*  ?????.?????
  a      ->  a
  a.b    ->  a.b
  a.b.c  ->  a.b
  part1.part2.part3  ->  part1.part2
  123456.123456.123456  (Not renamed because doesn't match sourceMask)

_नाम में अंतिम के बाद वर्ण बदलें और एक्सटेंशन को संरक्षित करने का प्रयास करें। ( _विस्तार में दिखाई देने पर ठीक से काम नहीं करता है )

ren  *_*  *_NEW.*
  abcd_12345.txt  ->  abcd_NEW.txt
  abc_newt_1.dat  ->  abc_newt_NEW.dat
  abcdef.jpg          (Not renamed because doesn't match sourceMask)
  abcd_123.a_b    ->  abcd_123.a_NEW  (not desired, but no simple RENAME form will work in this case)

किसी भी नाम को उन घटकों में विभाजित किया . जा सकता है जिन्हें वर्ण द्वारा सीमांकित किया जाता है, केवल प्रत्येक घटक के अंत से जोड़ा या हटाया जा सकता है। वाइल्डकार्ड के साथ शेष को संरक्षित करते हुए वर्णों को घटक के आरंभ या मध्य से हटाया या जोड़ा नहीं जा सकता। पदार्थ कहीं भी ले जाने की अनुमति है।

ren  ??????.??????.??????  ?x.????999.*rForTheCourse
  part1.part2            ->  px.part999.rForTheCourse
  part1.part2.part3      ->  px.part999.parForTheCourse
  part1.part2.part3.part4   (Not renamed because doesn't match sourceMask)
  a.b.c                  ->  ax.b999.crForTheCourse
  a.b.CarPart3BEER       ->  ax.b999.CarParForTheCourse

यदि संक्षिप्त नाम सक्षम हैं, तो ?नाम के लिए कम से कम 8 और ?विस्तार के लिए कम से कम 3 के साथ एक स्रोतमास्क सभी फाइलों से मेल खाएगा क्योंकि यह हमेशा छोटे 8.3 नाम से मेल खाएगा।

ren ????????.???  ?x.????999.*rForTheCourse
  part1.part2.part3.part4  ->  px.part999.part3.parForTheCourse


उपयोगी क्विर्क / बग? नाम उपसर्ग हटाने के लिए

यह सुपरयूजर पोस्ट बताती है कि कैसे /एक फ़ाइल नाम से अग्रणी वर्णों को हटाने के लिए फ़ॉरवर्ड स्लैश ( ) का एक सेट का उपयोग किया जा सकता है। प्रत्येक वर्ण को हटाने के लिए एक स्लैश आवश्यक है। मैंने विंडोज 10 मशीन पर व्यवहार की पुष्टि की है।

ren "abc-*.txt" "////*.txt"
  abc-123.txt        --> 123.txt
  abc-HelloWorld.txt --> HelloWorld.txt

यह तकनीक केवल तभी काम करती है जब स्रोत और लक्ष्य मास्क दोनों दोहरे उद्धरण चिह्नों में संलग्न हों। अपेक्षित उद्धरण के बिना निम्नलिखित सभी फॉर्म इस त्रुटि के साथ विफल होते हैं:The syntax of the command is incorrect

REM - All of these forms fail with a syntax error.
ren abc-*.txt "////*.txt"
ren "abc-*.txt" ////*.txt
ren abc-*.txt ////*.txt

/मध्यम या एक फ़ाइल नाम के अंत में कोई भी वर्ण दूर करने के लिए इस्तेमाल नहीं किया जा सकता है। यह केवल अग्रणी (उपसर्ग) वर्णों को निकाल सकता है।

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


संभव RENAME बग - एक एकल कमांड दो बार एक ही फ़ाइल का नाम बदल सकता है!

एक खाली परीक्षण फ़ोल्डर में शुरू:

C:\test>copy nul 123456789.123
        1 file(s) copied.

C:\test>dir /x
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of C:\test

09/15/2012  07:42 PM    <DIR>                       .
09/15/2012  07:42 PM    <DIR>                       ..
09/15/2012  07:42 PM                 0 123456~1.123 123456789.123
               1 File(s)              0 bytes
               2 Dir(s)  327,237,562,368 bytes free

C:\test>ren *1* 2*3.?x

C:\test>dir /x
 Volume in drive C is OS
 Volume Serial Number is EE2C-5A11

 Directory of C:\test

09/15/2012  07:42 PM    <DIR>                       .
09/15/2012  07:42 PM    <DIR>                       ..
09/15/2012  07:42 PM                 0 223456~1.XX  223456789.123.xx
               1 File(s)              0 bytes
               2 Dir(s)  327,237,562,368 bytes free

REM Expected result = 223456789.123.x

मेरा मानना ​​है कि sourceMask *1*पहले लंबे फ़ाइल नाम से मेल खाता है, और फ़ाइल का नाम बदलकर अपेक्षित परिणाम हो गया है 223456789.123.x। RENAME तब प्रक्रिया करने के लिए अधिक फ़ाइलों की तलाश में रहता है और नए संक्षिप्त नाम के माध्यम से नई नाम वाली फ़ाइल ढूंढता है 223456~1.X। फ़ाइल को फिर से नाम दिया जाता है और अंतिम परिणाम देता है 223456789.123.xx

यदि मैं 8.3 नाम पीढ़ी को अक्षम करता हूं तो RENAME अपेक्षित परिणाम देता है।

मैंने पूरी तरह से ट्रिगर स्थितियों में से पूरी तरह से काम नहीं किया है जो इस अजीब व्यवहार को प्रेरित करने के लिए मौजूद होना चाहिए। मुझे चिंता थी कि शायद कभी खत्म न होने वाले RENAME का निर्माण संभव हो, लेकिन मैं कभी भी प्रेरित नहीं कर पाया।

मेरा मानना ​​है कि निम्नलिखित सभी बग को प्रेरित करने के लिए सही होना चाहिए। मेरे द्वारा देखे गए प्रत्येक बिगड़े हुए मामले में निम्नलिखित स्थितियां थीं, लेकिन निम्नलिखित स्थितियों को पूरा करने वाले सभी मामलों को नहीं किया गया था।

  • लघु 8.3 नाम सक्षम होना चाहिए
  • SourceMask को मूल लंबे नाम से मेल खाना चाहिए।
  • प्रारंभिक नाम को एक छोटा नाम उत्पन्न करना चाहिए जो sourceMask से भी मेल खाता हो
  • प्रारंभिक नाम का संक्षिप्त नाम बाद में मूल संक्षिप्त नाम (यदि यह मौजूद था) की तुलना में क्रमबद्ध होना चाहिए?

6
क्या एक गहन उत्तर .. +1।
मध्यपूर्व में

विस्तृत रूप से विस्तृत!
एंड्री एम

13
इसके आधार पर, Microsoft को "उपयोग के लिए, सुपरसर्वरREN /? . com/a/475875 " को बस जोड़ना चाहिए ।
efotinis

4
@ सीएडी - यह उत्तर 100% मूल सामग्री है जिसे साइमन ने मेरे अनुरोध पर अपनी साइट पर शामिल किया था। उस SS64 पृष्ठ के नीचे देखें और आप देखेंगे कि साइमन मुझे काम का श्रेय देता है।
डेनभम

2
@ JacksOnF1re - मेरे जवाब में नई जानकारी / तकनीक जोड़ी गई। आप वास्तव में Copy of एक अस्पष्ट फॉरवर्ड स्लैश तकनीक का उपयोग करके अपने उपसर्ग को हटा सकते हैं :ren "Copy of *.txt" "////////*"
डेबनम

4

एक्सबुक के समान ही, सोर्सफाइल से लक्ष्य फ़ाइल नाम प्राप्त करने के लिए यहां C # कार्यान्वयन है।

मुझे debham के उदाहरणों में 1 छोटी त्रुटि मिली:

 ren  *_*  *_NEW.*
   abc_newt_1.dat  ->  abc_newt_NEW.txt (should be: abd_newt_NEW.dat)

यहाँ कोड है:

    /// <summary>
    /// Returns a filename based on the sourcefile and the targetMask, as used in the second argument in rename/copy operations.
    /// targetMask may contain wildcards (* and ?).
    /// 
    /// This follows the rules of: http://superuser.com/questions/475874/how-does-the-windows-rename-command-interpret-wildcards
    /// </summary>
    /// <param name="sourcefile">filename to change to target without wildcards</param>
    /// <param name="targetMask">mask with wildcards</param>
    /// <returns>a valid target filename given sourcefile and targetMask</returns>
    public static string GetTargetFileName(string sourcefile, string targetMask)
    {
        if (string.IsNullOrEmpty(sourcefile))
            throw new ArgumentNullException("sourcefile");

        if (string.IsNullOrEmpty(targetMask))
            throw new ArgumentNullException("targetMask");

        if (sourcefile.Contains('*') || sourcefile.Contains('?'))
            throw new ArgumentException("sourcefile cannot contain wildcards");

        // no wildcards: return complete mask as file
        if (!targetMask.Contains('*') && !targetMask.Contains('?'))
            return targetMask;

        var maskReader = new StringReader(targetMask);
        var sourceReader = new StringReader(sourcefile);
        var targetBuilder = new StringBuilder();


        while (maskReader.Peek() != -1)
        {

            int current = maskReader.Read();
            int sourcePeek = sourceReader.Peek();
            switch (current)
            {
                case '*':
                    int next = maskReader.Read();
                    switch (next)
                    {
                        case -1:
                        case '?':
                            // Append all remaining characters from sourcefile
                            targetBuilder.Append(sourceReader.ReadToEnd());
                            break;
                        default:
                            // Read source until the last occurrance of 'next'.
                            // We cannot seek in the StringReader, so we will create a new StringReader if needed
                            string sourceTail = sourceReader.ReadToEnd();
                            int lastIndexOf = sourceTail.LastIndexOf((char) next);
                            // If not found, append everything and the 'next' char
                            if (lastIndexOf == -1)
                            {
                                targetBuilder.Append(sourceTail);
                                targetBuilder.Append((char) next);

                            }
                            else
                            {
                                string toAppend = sourceTail.Substring(0, lastIndexOf + 1);
                                string rest = sourceTail.Substring(lastIndexOf + 1);
                                sourceReader.Dispose();
                                // go on with the rest...
                                sourceReader = new StringReader(rest);
                                targetBuilder.Append(toAppend);
                            }
                            break;
                    }

                    break;
                case '?':
                    if (sourcePeek != -1 && sourcePeek != '.')
                    {
                        targetBuilder.Append((char)sourceReader.Read());
                    }
                    break;
                case '.':
                    // eat all characters until the dot is found
                    while (sourcePeek != -1 && sourcePeek != '.')
                    {
                        sourceReader.Read();
                        sourcePeek = sourceReader.Peek();
                    }

                    targetBuilder.Append('.');
                    // need to eat the . when we peeked it
                    if (sourcePeek == '.')
                        sourceReader.Read();

                    break;
                default:
                    if (sourcePeek != '.') sourceReader.Read(); // also consume the source's char if not .
                    targetBuilder.Append((char)current);
                    break;
            }

        }

        sourceReader.Dispose();
        maskReader.Dispose();
        return targetBuilder.ToString().TrimEnd('.', ' ');
    }

और यहाँ उदाहरणों का परीक्षण करने के लिए एक NUnit परीक्षण विधि है:

    [Test]
    public void TestGetTargetFileName()
    {
        string targetMask = "?????.?????";
        Assert.AreEqual("a", FileUtil.GetTargetFileName("a", targetMask));
        Assert.AreEqual("a.b", FileUtil.GetTargetFileName("a.b", targetMask));
        Assert.AreEqual("a.b", FileUtil.GetTargetFileName("a.b.c", targetMask));
        Assert.AreEqual("part1.part2", FileUtil.GetTargetFileName("part1.part2.part3", targetMask));
        Assert.AreEqual("12345.12345", FileUtil.GetTargetFileName("123456.123456.123456", targetMask));

        targetMask = "A?Z*";
        Assert.AreEqual("AZ", FileUtil.GetTargetFileName("1", targetMask));
        Assert.AreEqual("A2Z", FileUtil.GetTargetFileName("12", targetMask));
        Assert.AreEqual("AZ.txt", FileUtil.GetTargetFileName("1.txt", targetMask));
        Assert.AreEqual("A2Z.txt", FileUtil.GetTargetFileName("12.txt", targetMask));
        Assert.AreEqual("A2Z", FileUtil.GetTargetFileName("123", targetMask));
        Assert.AreEqual("A2Z.txt", FileUtil.GetTargetFileName("123.txt", targetMask));
        Assert.AreEqual("A2Z4", FileUtil.GetTargetFileName("1234", targetMask));
        Assert.AreEqual("A2Z4.txt", FileUtil.GetTargetFileName("1234.txt", targetMask));

        targetMask = "*.txt";
        Assert.AreEqual("a.txt", FileUtil.GetTargetFileName("a", targetMask));
        Assert.AreEqual("b.txt", FileUtil.GetTargetFileName("b.dat", targetMask));
        Assert.AreEqual("c.x.txt", FileUtil.GetTargetFileName("c.x.y", targetMask));

        targetMask = "*?.bak";
        Assert.AreEqual("a.bak", FileUtil.GetTargetFileName("a", targetMask));
        Assert.AreEqual("b.dat.bak", FileUtil.GetTargetFileName("b.dat", targetMask));
        Assert.AreEqual("c.x.y.bak", FileUtil.GetTargetFileName("c.x.y", targetMask));

        targetMask = "*_NEW.*";
        Assert.AreEqual("abcd_NEW.txt", FileUtil.GetTargetFileName("abcd_12345.txt", targetMask));
        Assert.AreEqual("abc_newt_NEW.dat", FileUtil.GetTargetFileName("abc_newt_1.dat", targetMask));
        Assert.AreEqual("abcd_123.a_NEW", FileUtil.GetTargetFileName("abcd_123.a_b", targetMask));

        targetMask = "?x.????999.*rForTheCourse";

        Assert.AreEqual("px.part999.rForTheCourse", FileUtil.GetTargetFileName("part1.part2", targetMask));
        Assert.AreEqual("px.part999.parForTheCourse", FileUtil.GetTargetFileName("part1.part2.part3", targetMask));
        Assert.AreEqual("ax.b999.crForTheCourse", FileUtil.GetTargetFileName("a.b.c", targetMask));
        Assert.AreEqual("ax.b999.CarParForTheCourse", FileUtil.GetTargetFileName("a.b.CarPart3BEER", targetMask));

    }

मेरे उदाहरण में गलती के बारे में सिर के लिए धन्यवाद। मैंने इसे ठीक करने के लिए अपना उत्तर संपादित कर दिया है।
डेबनहम

1

शायद कोई इसे उपयोगी पा सकता है। यह जावास्क्रिप्ट कोड ऊपर dbenham द्वारा उत्तर पर आधारित है।

मैंने sourceMaskबहुत परीक्षण नहीं किया , लेकिन targetMaskडेंभम द्वारा दिए गए सभी उदाहरणों से मेल खाता है।

function maskMatch(path, mask) {
    mask = mask.replace(/\./g, '\\.')
    mask = mask.replace(/\?/g, '.')
    mask = mask.replace(/\*/g, '.+?')
    var r = new RegExp('^'+mask+'$', '')
    return path.match(r)
}

function maskNewName(path, mask) {
    if (path == '') return
    var x = 0, R = ''
    for (var m = 0; m < mask.length; m++) {
        var ch = mask[m], q = path[x], z = mask[m + 1]
        if (ch != '.' && ch != '*' && ch != '?') {
            if (q && q != '.') x++
            R += ch
        } else if (ch == '?') {
            if (q && q != '.') R += q, x++
        } else if (ch == '*' && m == mask.length - 1) {
            while (x < path.length) R += path[x++]
        } else if (ch == '*') {
            if (z == '.') {
                for (var i = path.length - 1; i >= 0; i--) if (path[i] == '.') break
                if (i < 0) {
                    R += path.substr(x, path.length) + '.'
                    i = path.length
                } else R += path.substr(x, i - x + 1)
                x = i + 1, m++
            } else if (z == '?') {
                R += path.substr(x, path.length), m++, x = path.length
            } else {
                for (var i = path.length - 1; i >= 0; i--) if (path[i] == z) break
                if (i < 0) R += path.substr(x, path.length) + z, x = path.length, m++
                else R += path.substr(x, i - x), x = i + 1
            }
        } else if (ch == '.') {
            while (x < path.length) if (path[x++] == '.') break
            R += '.'
        }
    }
    while (R[R.length - 1] == '.') R = R.substr(0, R.length - 1)
}

0

मैंने वाइल्डकार्ड फाइलनाम को मास्क करने के लिए BASIC में यह कोड लिखने में कामयाबी हासिल की है:

REM inputs a filename and matches wildcards returning masked output filename.
FUNCTION maskNewName$ (path$, mask$)
IF path$ = "" THEN EXIT FUNCTION
IF INSTR(path$, "?") OR INSTR(path$, "*") THEN EXIT FUNCTION
x = 0
R$ = ""
FOR m = 0 TO LEN(mask$) - 1
    ch$ = MID$(mask$, m + 1, 1)
    q$ = MID$(path$, x + 1, 1)
    z$ = MID$(mask$, m + 2, 1)
    IF ch$ <> "." AND ch$ <> "*" AND ch$ <> "?" THEN
        IF LEN(q$) AND q$ <> "." THEN x = x + 1
        R$ = R$ + ch$
    ELSE
        IF ch$ = "?" THEN
            IF LEN(q$) AND q$ <> "." THEN R$ = R$ + q$: x = x + 1
        ELSE
            IF ch$ = "*" AND m = LEN(mask$) - 1 THEN
                WHILE x < LEN(path$)
                    R$ = R$ + MID$(path$, x + 1, 1)
                    x = x + 1
                WEND
            ELSE
                IF ch$ = "*" THEN
                    IF z$ = "." THEN
                        FOR i = LEN(path$) - 1 TO 0 STEP -1
                            IF MID$(path$, i + 1, 1) = "." THEN EXIT FOR
                        NEXT
                        IF i < 0 THEN
                            R$ = R$ + MID$(path$, x + 1) + "."
                            i = LEN(path$)
                        ELSE
                            R$ = R$ + MID$(path$, x + 1, i - x + 1)
                        END IF
                        x = i + 1
                        m = m + 1
                    ELSE
                        IF z$ = "?" THEN
                            R$ = R$ + MID$(path$, x + 1, LEN(path$))
                            m = m + 1
                            x = LEN(path$)
                        ELSE
                            FOR i = LEN(path$) - 1 TO 0 STEP -1
                                'IF MID$(path$, i + 1, 1) = z$ THEN EXIT FOR
                                IF UCASE$(MID$(path$, i + 1, 1)) = UCASE$(z$) THEN EXIT FOR
                            NEXT
                            IF i < 0 THEN
                                R$ = R$ + MID$(path$, x + 1, LEN(path$)) + z$
                                x = LEN(path$)
                                m = m + 1
                            ELSE
                                R$ = R$ + MID$(path$, x + 1, i - x)
                                x = i + 1
                            END IF
                        END IF
                    END IF
                ELSE
                    IF ch$ = "." THEN
                        DO WHILE x < LEN(path$)
                            IF MID$(path$, x + 1, 1) = "." THEN
                                x = x + 1
                                EXIT DO
                            END IF
                            x = x + 1
                        LOOP
                        R$ = R$ + "."
                    END IF
                END IF
            END IF
        END IF
    END IF
NEXT
DO WHILE RIGHT$(R$, 1) = "."
    R$ = LEFT$(R$, LEN(R$) - 1)
LOOP
R$ = RTRIM$(R$)
maskNewName$ = R$
END FUNCTION

4
क्या आप स्पष्ट कर सकते हैं कि इस सवाल में क्या जवाब दिया गया था?
फिक्सर 1234

यह फ़ंक्शन REN का उपयोग करता है, जैसे कि REN * .TMP *। प्रसंस्करण जैसे वाइल्डकार्ड मिलान के लिए उपयोग करता है। यह इस बात पर निर्भर करता है कि फ़ाइल नाम बदलने से पहले फ़ंक्शन को कैसे कहा जाता है।
ईकोसन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.