سؤال كيف يقوم الأمر Windows RENAME بتفسير أحرف البدل؟


كيف يقوم الأمر Windows RENAME (REN) بتفسير أحرف البدل؟

مرفق المساعدة المبني لا يساعد - فهو لا يعالج أحرف البدل على الإطلاق.

ال مايكروسوفت تيكنت XP مساعدة على الانترنت ليس أفضل بكثير. هنا هو كل ما يقوله بشأن أحرف البدل:

"يمكنك استخدام أحرف البدل (* و ?) في أي من معلمات اسم الملف. إذا كنت تستخدم أحرف البدل في filename2 ، فإن الأحرف التي تمثلها أحرف البدل تكون مطابقة للأحرف المقابلة في filename1. "

ليس هناك الكثير من المساعدة - هناك العديد من الطرق التي يمكن تفسير العبارة.

لقد نجحت في استخدام أحرف البدل في filename2 المعلمة في بعض المناسبات ، لكنها كانت دائما التجربة والخطأ. لم أكن قادرة على توقع ما ينجح وما لا ينجح. في كثير من الأحيان ، اضطررت إلى كتابة نص برمجي صغير مع حلقة FOR تقوم بتوزيع كل اسم حتى أتمكن من بناء كل اسم جديد حسب الحاجة. غير مريحة للغاية.

إذا كنت أعرف قواعد كيفية معالجة أحرف البدل ، فأنا أظن أنه يمكنني استخدام الأمر RENAME بشكل أكثر فاعلية دون الحاجة إلى اللجوء إلى الدُفعة في كثير من الأحيان. وبالطبع فإن معرفة القواعد من شأنها أن تفيد أيضًا تطوير الدفعات.

(نعم - هذه حالة أقوم فيها بنشر سؤال وجواب إقرانين. لقد سئمت من عدم معرفة القواعد وقررت أن أجربها بنفسى. أظن أن كثيرين آخرين قد يكونون مهتمين بما اكتشفته)


68
2017-09-16 13:59


الأصل


هناك أكوام من الأمثلة الجيدة حول كيفية إعادة التسمية باستخدام أحرف البدل هنا: lagmonster.org/docs/DOS7/z-ren1.html - Matthew Lock
MatthewLock - ارتباط مثير للاهتمام ، ولكن تلك القواعد والأمثلة هي لـ MSDOS 7 ، ليس شبابيك. هناك اختلافات كبيرة. على سبيل المثال ، لا يسمح MSDOS بإلحاق الأحرف الإضافية بعد *، ويندوز يفعل. هذا له عواقب وخيمة. أتمنى لو كنت قد عرفت عن هذا الموقع رغم ذلك ؛ ربما جعل تحقيقي أسهل. تختلف قواعد MSDOS7 بشكل ملحوظ عن قواعد DOS القديمة قبل أسماء الملفات الطويلة ، وهي خطوة في اتجاه كيفية معالجة Windows لها. كنت قد وجدت قواعد ما قبل اسم ملف DOS الطويل ، وكانت عديمة القيمة للتحقيق. - dbenham
لم اكن اعرف ذلك ؛) - Matthew Lock


الأجوبة:


تم اكتشاف هذه القواعد بعد إجراء اختبارات مكثفة على جهاز Vista. تم إجراء أي اختبارات مع unicode في أسماء الملفات.

يتطلب RENAME معلمتين - وهي sourceMask ، يتبعها targetMask. يمكن أن يحتوي كل من sourceMask و targetMask * و / أو ? البدل. يتغير سلوك أحرف البدل قليلاً بين أقنعة المصدر والهدف.

ملحوظة - يمكن استخدام REN لإعادة تسمية مجلد ، ولكن أحرف البدل هي ليس مسموح به في sourceMask أو targetMask عند إعادة تسمية مجلد. إذا تطابق sourceMask ملف واحد على الأقل ، فسيتم إعادة تسمية الملف (الملفات) وسيتم تجاهل المجلدات. إذا كان sourceMask يطابق المجلدات فقط وليس الملفات ، فسيتم إنشاء خطأ في بناء الجملة إذا ظهرت أحرف البدل في المصدر أو الهدف. إذا كان sourceMask لا يطابق أي شيء ، عندئذٍ ينتج عن الخطأ "لم يتم العثور على الملف".

أيضاً ، عند إعادة تسمية الملفات ، يتم السماح أحرف البدل فقط في جزء اسم الملف من sourceMask. أحرف البدل غير مسموح بها في المسار الذي يؤدي إلى اسم الملف.

sourceMask

يعمل sourceMask كعامل تصفية لتحديد الملفات التي تمت إعادة تسميتها. تعمل أحرف البدل هنا تمامًا مثل أي أمر آخر يقوم بتصفية أسماء الملفات.

  • ? - يتطابق مع أي حرف 0 أو 1 إلا  .  هذا حرف البدل هو الجشع - يستهلك دائما الحرف التالي إذا لم يكن .  ومع ذلك فإنه سيطابق أي شيء دون فشل إذا كان في نهاية الاسم أو إذا كان الحرف التالي هو .

  • * - يتطابق مع أي حرف أو أكثر بما فيها  . (مع استثناء واحد أدناه). هذا حرف البدل ليس الجشع. سيطابق قليلاً أو بقدر ما يلزم لتمكين الأحرف التالية لتتطابق.

يجب أن تتطابق جميع الأحرف غير البدلمة مع نفسها ، مع بعض استثناءات الحالات الخاصة.

  • . - يتطابق مع نفسه أو يمكن أن تتطابق مع نهاية الاسم (لا شيء) إذا لم يتبق المزيد من الأحرف. (ملاحظة - لا يمكن أن ينتهي اسم Windows صالح .)

  • {space} - يتطابق مع نفسه أو يمكن أن تتطابق مع نهاية الاسم (لا شيء) إذا لم يتبق المزيد من الأحرف. (ملاحظة - لا يمكن أن ينتهي اسم Windows صالح {space})

  • *. في النهاية - تتطابق مع أي حرف أو أكثر إلا  .  الإنهاء . يمكن أن يكون في الواقع أي مزيج من . و {space} طالما أن آخر حرف في القناع هو .  هذا هو الاستثناء الوحيد والوحيد * لا يتطابق ببساطة مع أي مجموعة من الأحرف.

القواعد المذكورة أعلاه ليست معقدة. ولكن هناك قاعدة واحدة أكثر أهمية من شأنها أن تجعل الوضع مربكًا: تتم مقارنة SourceMask بالاسم الطويل والاسم القصير 8.3 (إن وجد). يمكن أن تجعل هذه القاعدة الأخيرة تفسير النتائج صعبة للغاية ، لأنه ليس من الواضح دائمًا عند مطابقة القناع عن طريق الاسم المختصر.

من الممكن استخدام RegEdit لتعطيل إنشاء أسماء 8.3 قصيرة على وحدات تخزين NTFS ، عندها يتم تفسير نتائج قناع الملف بشكل مستقيم. أي أسماء قصيرة تم إنشاؤها قبل تعطيل الأسماء القصيرة ستبقى.

targetMask

ملاحظة - لم أقم بإجراء أي اختبار دقيق ، ولكن يبدو أن هذه القواعد نفسها تعمل أيضًا على الاسم المستهدف لخاصية COPY commmand

تحدد targetMask الاسم الجديد. يتم تطبيقه دائمًا على الاسم الكامل الطويل ؛ لا يتم تطبيق targetMask أبدًا على الاسم القصير 8.3 ، حتى إذا تطابق الاسم المصدر مع الاسم القصير 8.3.

لا يؤثر وجود أو عدم ظهور أحرف البدل في sourceMask على كيفية معالجة أحرف البدل في targetMask.

في المناقشة التالية - c يمثل أي شخصية ليست كذلك *، ?أو .

تتم معالجة TargetMask مقابل اسم المصدر بشكل صارم من اليسار إلى اليمين بدون أي تتبع للخلف.

  • c - تقدم الموضع ضمن اسم المصدر طالما لا يكون الحرف التالي . ويلحق c إلى اسم الهدف. (يستبدل الحرف الذي كان في المصدر مع cولكن لا تستبدل أبدًا .)

  • ? - يطابق الحرف التالي من الاسم الطويل للمصدر ويضيفه إلى اسم الهدف طالما أن الحرف التالي ليس كذلك .  إذا كان الحرف التالي هو . أو إذا كان في نهاية اسم المصدر ثم يتم إضافة أي حرف إلى النتيجة ولا يتم تغيير الموضع الحالي ضمن اسم المصدر.

  • * في نهاية targetMask - إلحاق جميع الأحرف المتبقية من المصدر إلى الهدف. إذا كان بالفعل في نهاية المصدر ، فعندئذ لا يفعل شيئًا.

  • *c - يتطابق مع جميع حروف المصدر من الموضع الحالي حتى آخر لحظة من c (يطابق الجشع حالة حساسة) ويلحق مجموعة متطابقة من الأحرف إلى اسم الهدف. إذا c لم يتم العثور على ، ثم يتم إلحاق جميع الأحرف المتبقية من المصدر ، متبوعة بـ cهذا هو الموقف الوحيد الذي أعرفه حيث يكون تطابق نمط ملفات Windows حساسًا لحالة الأحرف.

  • *. - يتطابق مع جميع حروف المصدر من الموضع الحالي عبر الاخير من . (تطابق الجشع) ويضيف مجموعة الأحرف المطابقة إلى اسم الهدف. إذا . لم يتم العثور على ، ثم يتم إلحاق جميع الأحرف المتبقية من المصدر ، متبوعة بـ .

  • *? - إلحاق جميع الأحرف المتبقية من المصدر إلى الهدف. إذا كان بالفعل في نهاية المصدر لا يفعل شيئا.

  • . بدون * في المقدمة - تقدم الموقف في المصدر من خلال أول من . دون نسخ أي أحرف ، ويلحق . إلى اسم الهدف. إذا . لم يتم العثور عليه في المصدر ، ثم يتقدم إلى نهاية المصدر ويضيف . إلى اسم الهدف.

بعد استنفاد mainMask ، أي زائدة . و {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 أحرف بحيث لا يتم اقتطاعها. (من الواضح أنه يمكن إضافة إضافية ? على طرفي "targetMask" للحفاظ على الأسماء والإضافات حتى 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)

يمكن تقسيم أي اسم إلى مكونات محددة بواسطة .  يمكن فقط إلحاق الأحرف أو حذفها من نهاية كل مكون. لا يمكن حذف الحروف أو إضافتها إلى بداية أو وسط المكون مع الاحتفاظ بالبقية باستخدام أحرف البدل. يسمح بدائل في أي مكان.
تصحيح  - تم إصلاح هذا المثال. يحتوي الإصدار الأقدم على معلومات غير صحيحة بخصوص sourceMasks غير متطابقة

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


quirk / علة مفيدة؟ لحذف بادئات الأسماء

هذا العضو SuperUser يصف كيف مجموعة من مائلة للأمام (/) يمكن استخدامها لحذف الأحرف الرائدة من اسم ملف. يلزم وجود شرطة مائلة واحدة لكل حرف يتم حذفه. لقد أكدت السلوك على جهاز Windows 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 إلى النتيجة المتوقعة.

لم أقم بتطبيق جميع الشروط المسبقة التي يجب أن تكون موجودة للحث على هذا السلوك الغريب. كنت قلقة من أنه قد يكون من الممكن إنشاء إعادة تسمية متكررة لا تنتهي أبداً ، لكنني لم أتمكن أبدًا من حث أحدها.

أعتقد أن كل ما يلي يجب أن يكون صحيحًا للحث على الخطأ. كان كل حالة رأيت رأيت في حالة من الحالات التالية ، ولكن لم يتم التنصت على جميع الحالات التي تفي بالشروط التالية.

  • يجب تمكين أسماء 8.3 القصيرة
  • يجب أن تطابق sourceMask الاسم الطويل الأصلي.
  • يجب أن يقوم الاسم المبدئي بإعادة تسمية اسم قصير يطابق أيضاً sourceMask
  • يجب أن يكون الاسم المختصر الأول المعاد تسميته مرتبًا بعد الاسم المختصر الأصلي (إذا كان موجودًا؟)

106
2017-09-16 14:00



ما إجابة شاملة .. +1. - meder omuraliev
بتفصيل شديد! - Andriy M
وبناءً على هذا ، يجب على Microsoft إضافة "For use، see superuser.com/a/475875 " في REN /?. - efotinis
CAD - هذه الإجابة عبارة عن محتوى أصلي 100٪ ضمّنه سيمون على موقعه بناءً على طلبي. انظر إلى أسفل صفحة SS64 هذه وستلاحظ أن سايمون يعطيني الفضل في العمل. - dbenham
@ JacksOnF1re - إضافة معلومات / تقنية جديدة إلى جوابي. يمكنك فعلا حذف الخاص بك Copy of  البادئة باستخدام تقنية مائلة مائلة للأمام: ren "Copy of *.txt" "////////*" - dbenham


على غرار ما يحدث في الكمبيوتر المحمول ، إليك تطبيق C # للحصول على اسم الملف المستهدف من ملف المصدر.

عثرت على خطأ صغير واحد في أمثلة dbenham:

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

    }

3
2017-12-16 10:13



شكرا لرئيس حول الخطأ في المثال الخاص بي. قمت بتحرير إجابتي لإصلاحها. - dbenham


ربما يمكن لشخص ما أن يجد هذا مفيدًا. يعتمد رمز جافا سكريبت هذا على الإجابة من قبل dbenham أعلاه.

لم اختبر sourceMask كثيرا جدا ، ولكن targetMask يتطابق مع جميع الأمثلة التي قدمها dbenham.

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

1
2018-04-09 17:07





لقد تمكنت من كتابة هذا الرمز في 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

0
2017-10-13 01:27



هل يمكنك توضيح كيف يجيب هذا على ما تم طرحه في السؤال؟ - fixer1234
يقوم بإجراء نسخ متماثل الدالة REN يستخدم لمطابقة أحرف البدل مثل معالجة REN * .TMP * .DOC استناداً إلى كيفية استدعاء الدالة قبل إعادة تسمية أسماء الملفات. - eoredson