Як команда Windows RENAME інтерпретує підстановку?


77

Як команда Windows RENAME (REN) інтерпретує символи для марок?

Вбудований засіб HELP не допомагає - він взагалі не стосується макетів.

Microsoft TechNet XP онлайн допомогу не набагато краще. Ось усе, що можна сказати про макіяж символів:

Msgstr "Ви можете використовувати підстановку ( *і ?) в будь-якому параметрі імені файлу. Якщо ви використовуєте підстановку в імені файлу2, символи, представлені символами підстановки, будуть ідентичними відповідним символам у імені файлу1."

Немало допомоги - є багато способів інтерпретації твердження.

Мені вдалося в деяких випадках успішно використовувати підстановку в параметрі filename2 , але це завжди було спроб та помилок. Я не міг передбачити, що працює, а що ні. Часто мені доводилося вдаватися до написання невеликого пакетного сценарію зі шлейфом FOR, який аналізує кожне ім’я, щоб я міг будувати кожне нове ім'я за потребою. Не дуже зручно.

Якби я знав правила того, як обробляються підстановки, тоді я вважаю, що міг би більш ефективно використовувати команду RENAME, не маючи намір так часто вдаватися до партії. Звичайно, знання правил також спричинить користь розвитку партії.

(Так - це випадок, коли я розміщую парне запитання і відповідь. Я втомився не знати правил і вирішив самостійно експериментувати. Я думаю, що багатьох інших може зацікавити те, що я виявив)



5
@MatthewLock - Цікаве посилання, але ці правила та приклади призначені для MSDOS 7, а не для Windows. Є суттєві відмінності. Наприклад, MSDOS не дозволяє додавати додаткові символи після *, як це робить Windows. Це має величезні наслідки. Хочеться, щоб я знав про цей сайт; це могло б полегшити моє розслідування. Правила MSDOS7 істотно відрізняються від старих правил DOS перед довгими іменами файлів, і вони є кроком у напрямку того, як Windows обробляє їх. Я знайшов заздалегідь довгі правила назви файлів DOS, і вони були марними для мого розслідування.
dbenham

Я цього не знав;)
Метью Лок

Відповіді:


116

Ці правила були виявлені після проведення широких випробувань на машині Vista. Жодних тестів з unicode в іменах файлів не робилося.

RENAME вимагає 2 параметрів - sourceMask, за яким слід targetMask. Як sourceMask, так і targetMask можуть містити *та / або ?символи. Поведінка макіяжів незначно змінюється між вихідними та цільовими масками.

Примітка - REN може використовуватися для перейменування папки, але символи підказки не дозволяються ні в sourceMask, ні в targetMask при перейменуванні папки. Якщо sourceMask відповідає щонайменше одному файлу, то файли (файли) будуть перейменовані, а папки будуть проігноровані. Якщо sourceMask відповідає лише папкам, а не файлам, то помилка синтаксису генерується, якщо у вихідному чи цільовому вигляді з’являються підмітні знаки. Якщо sourceMask нічого не відповідає, результати помилки "файл не знайдено".

Крім того, під час перейменування файлів підстановки дозволені лише у частині імені файлу sourceMask. Підстановочні знаки не дозволені в шляху, що веде до імені файлу.

sourceMask

SourceMask працює як фільтр, щоб визначити, які файли перейменовані. Підстановочні символи працюють тут так само, як і в будь-якій іншій команді, яка фільтрує назви файлів.

  • ?- відповідає будь-якому символу 0 або 1, за винятком . цієї підстановки - жадібна - вона завжди споживає наступного символу, якщо він не є. . Однак він не відповідає нічого безвідмовно, якщо в кінці імені або якщо наступний символ.

  • *- відповідає будь-якому 0 або більше символів, включаючи . (за винятком нижче). Ця підказка не жадібна. Він збігатиметься так само мало або стільки, скільки потрібно, щоб дати можливість наступним символам збігатися.

Усі символи, що не мають підказки, повинні відповідати самим собі, за винятком кількох спеціальних випадків.

  • .- Матч сам, або він може відповідати кінці імені (нічого), якщо більше символів не залишиться. (Примітка - дійсне ім'я Windows не може закінчуватися .)

  • {space}- Матч сам, або він може відповідати кінці імені (нічого), якщо більше символів не залишиться. (Примітка - дійсне ім'я Windows не може закінчуватися {space})

  • *.в кінці - відповідає будь-якому 0 або більше символів, за винятком . Закінчення .може насправді бути будь-якою комбінацією .та до {space}тих пір, поки самий останній символ у масці - . це єдиний і єдиний виняток, де *не просто відповідає жодному набору символів.

Наведені вище правила не такі складні. Але є ще одне дуже важливе правило, яке робить ситуацію заплутаною: SourceMask порівнюється як з довгим ім'ям, так і з коротким 8.3 ім'ям (якщо воно існує). Це останнє правило може зробити інтерпретацію результатів дуже хитрою, оскільки не завжди очевидно, коли маска збігається через коротке ім'я.

RegEdit можна використовувати для відключення генерації коротких 8,3 імен на томах NTFS, і тоді інтерпретація результатів маски файлів стає набагато більш прямою. Будь-які короткі імена, створені до відключення коротких імен, залишаться.

targetMask

Примітка. Я не робив жодного жорсткого тестування, але, схоже, ці самі правила також працюють для цільової назви команди COPY

Цільова маска вказує нову назву. Він завжди застосовується до повного довгого найменування; Цільова маска ніколи не застосовується до короткого імені 8.3, навіть якщо sourceMask збігається з коротким іменем 8.3.

Наявність або відсутність підстановочних кодів у вихідній масці не впливає на те, як обробляються подвійні символи в цільовій масці.

В подальшому обговоренні - cбудь-який символ , який не є *, ?або.

Цільова маска обробляється проти імені джерела суворо зліва направо, без зворотного відстеження.

  • c- Просуває позицію в імені джерела до тих пір, поки наступного символу немає, .і додає cдо цільового імені. (Замінює символ, який був у джерелі c, але ніколи не замінює .)

  • ?- Відповідає наступному символу з довгого імені джерела і додає його до цільового імені, доки наступний символ не є. . Якщо наступним символом є .або, якщо в кінці імені джерела, тоді до результату та поточного символу не додається жоден символ положення в назві джерела не змінюється.

  • *наприкінці targetMask - додає всі залишилися символи від джерела до цілі. Якщо вже в кінці джерела, то нічого не робить.

  • *c- Відповідає всім вихідним символам з поточного положення через останнє значення c(жадібне до регістру жадне збіг) і додає відповідне набір символів до цільового імені. Якщо cйого не знайдено, додаються всі залишилися символи з джерела, а потім c - це єдина ситуація, про яку я знаю, де відповідність шаблонів файлів Windows залежить від регістру.

  • *.- Відповідає всім вихідним символам з поточного положення через останню появу .(жадібна відповідність) і додає відповідне набір символів до цільового імені. Якщо .його не знайдено, додаються всі залишилися символи з джерела, а потім -.

  • *?- додає всі інші символи від джерела до цілі. Якщо вже в кінці джерела, то нічого не робить.

  • .без *попереду - переміщує позицію в джерелі через першу появу .без копіювання жодних символів та додає .до імені цілі. Якщо .його не знайдено в джерелі, тоді переходить до кінця джерела та додає .до цільового імені.

Після того, як targetMask вичерпано, будь-який трейлінг .і {space}обрізається в кінці отриманого цільового імені, оскільки імена файлів Windows не можуть закінчуватися .або{space}

Деякі практичні приклади

Замініть символ на 1-й і 3-й позиціях до будь-якого розширення (додайте 2-го або 3-го символу, якщо його ще немає)

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)

Будь-яке ім'я може бути розбито на компоненти, які обмежені символами, . можуть бути додані або видалені лише з кінця кожного компонента. Символи не можуть бути видалені з або додані до початку або середини компонента, зберігаючи залишки за допомогою символів. Заміни дозволені в будь-якому місці.

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

Якщо ввімкнено короткі імена, то sourceMask з принаймні 8 ?для імені та щонайменше 3 ?для розширення буде відповідати всім файлам, оскільки він завжди буде відповідати короткому 8.3.

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


Корисна примха / помилка? для видалення префіксів імен

У цій публікації 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 дає очікуваний результат.

Я не повністю розробив усі умови спрацювання, які повинні існувати, щоб викликати цю дивну поведінку. Я був стурбований тим, що можливо створити ніколи не закінчується рекурсивний RENAME, але я ніколи не зміг викликати його.

Я вважаю, що всі наведені нижче дії повинні бути правдивими, щоб викликати помилку. Кожна випадкова помилка, яку я бачив, мала такі умови, але не всі випадки, які відповідали цим умовам, були помилками.

  • Потрібно ввімкнути короткі 8,3 імені
  • SourceMask повинен відповідати початковому довгому імені.
  • Початкове перейменування повинно генерувати коротке ім'я, яке також відповідає sourceMask
  • Початкове перейменоване коротке ім’я повинно впорядковуватися пізніше початкового короткого імені (якщо воно існувало?)

6
Яка ґрунтовна відповідь .. +1.
meder omuraliev

Надзвичайно вишуканий!
Андрій М

13
Виходячи з цього, Microsoft повинна просто додати "Про використання, див. Superuser.com/a/475875 " в REN /?.
efotinis

4
@CAD - Ця відповідь є 100% оригінальним вмістом, який Саймон включив на свій сайт на мій запит. Подивіться внизу цієї сторінки SS64, і побачите, що Саймон дає мені заслугу за роботу.
dbenham

2
@ JacksOnF1re - до моєї відповіді додана нова інформація / техніка. Ви можете фактично видалити свій Copy of префікс, використовуючи незрозумілу техніку ren "Copy of *.txt" "////////*"
нахилу

4

Як і у програмі Exebook, ось реалізація C #, щоб отримати цільове ім'я файлу з вихідного файлу.

Я знайшов 1 невелику помилку в прикладах 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));

    }

Дякую за голову щодо помилки в моєму прикладі. Я відредагував свою відповідь, щоб її виправити.
dbenham

1

Можливо, хтось може вважати це корисним. Цей код JavaScript заснований на відповіді 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)
}

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
Чи можете ви уточнити, як це відповідає на те, що було задано у запитанні?
fixer1234

Він реплікує функцію, яку REN використовує для відповідності підстановочних кодів, таких як обробка REN * .TMP * .DOC, залежно від того, як функція викликається перед перейменуванням імен файлів.
eoredson
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.