Windows RENAME 명령은 와일드 카드를 어떻게 해석합니까?


77

Windows RENAME (REN) 명령은 와일드 카드를 어떻게 해석합니까?

내장 된 HELP 기능은 도움이되지 않습니다. 와일드 카드를 전혀 다루지 않습니다.

마이크로 소프트 TechNet의 XP 온라인 도움말은 훨씬 더하지 않습니다. 와일드 카드와 관련하여해야 할 모든 내용은 다음과 같습니다.

" 파일 이름 매개 변수에 와일드 카드 ( *?)를 사용할 수 있습니다 . filename2에 와일드 카드를 사용하면 와일드 카드로 표시되는 문자는 filename1의 해당 문자와 ​​동일합니다."

별로 도움이되지 않습니다-진술을 해석 할 수있는 많은 방법이 있습니다.

경우에 따라 filename2 매개 변수에 와일드 카드를 성공적으로 사용 했지만 항상 시행 착오를 거쳤습니다. 나는 무엇이 효과적이고 무엇이 효과가 없는지를 예상 할 수 없었습니다. 필자는 필요에 따라 각 새 이름을 작성할 수 있도록 각 이름을 구문 분석하는 FOR 루프를 사용하여 작은 배치 스크립트를 작성해야했습니다. 매우 편리하지 않습니다.

와일드 카드 처리 방법에 대한 규칙을 알고 있으면 배치에 자주 의존하지 않고도 RENAME 명령을보다 효과적으로 사용할 수 있다고 생각합니다. 물론 규칙을 아는 것도 배치 개발에 도움이 될 것입니다.

(예-이것은 한 쌍의 질문과 답변을 게시하는 경우입니다. 규칙을 알지 못하는 것에 지 쳤고 스스로 실험 해보기로 결정했습니다. 다른 많은 사람들이 내가 발견 한 것에 관심이있을 수 있습니다)


와일드 카드로 이름을 바꾸는 좋은 예가 여기 있습니다 : lagmonster.org/docs/DOS7/z-ren1.html
Matthew Lock

5
@MatthewLock-흥미로운 링크이지만 이러한 규칙과 예제는 Windows가 아닌 MSDOS 7에 대한 것 입니다. 중요한 차이점이 있습니다. 예를 들어, MSDOS는 *Windows 다음에 추가 문자를 추가 할 수 없습니다 . 그것은 큰 결과를 초래합니다. 나는 그 사이트에 대해 알고 있었으면 좋겠다. 내 조사가 더 쉬워 졌을 수도 있습니다. MSDOS7 규칙은 긴 파일 이름 이전의 이전 DOS 규칙과 크게 다르며 Windows에서이를 처리하는 방법의 단계입니다. 나는 DOS 규칙 이전의 긴 파일 이름을 찾았으며 조사 할 가치가 없었습니다.
dbenham

나는 몰랐다;)
Matthew Lock

답변:


116

이러한 규칙은 Vista 시스템에서 광범위한 테스트를 거친 후에 발견되었습니다. 파일 이름의 유니 코드로 테스트를 수행하지 않았습니다.

RENAME에는 sourceMask와 targetMask가 뒤에 오는 2 개의 매개 변수가 필요합니다. sourceMask 및 targetMask 모두 포함 할 수 있습니다 *및 / 또는 ?와일드 카드. 와일드 카드의 동작은 소스 마스크와 대상 마스크 사이에서 약간 변경됩니다.

REN을 사용하여 폴더 이름을 바꿀 수 있지만 폴더 이름을 바꿀 때 sourceMask 또는 targetMask에서 와일드 카드를 사용할없습니다 . sourceMask가 하나 이상의 파일과 일치하면 파일 이름이 바뀌고 폴더는 무시됩니다. sourceMask가 파일이 아닌 폴더 만 일치하면 소스 또는 대상에 와일드 카드가 표시되면 구문 오류가 발생합니다. sourceMask와 일치하는 것이 없으면 "파일을 찾을 수 없음"오류가 발생합니다.

또한 파일 이름을 바꿀 때 와일드 카드는 sourceMask의 파일 이름 부분에서만 허용됩니다. 파일 이름으로 이어지는 경로에는 와일드 카드를 사용할 수 없습니다.

소스 마스크

sourceMask는 이름을 바꿀 파일을 결정하는 필터 역할을합니다. 여기서 와일드 카드는 파일 이름을 필터링하는 다른 명령과 동일하게 작동합니다.

  • ?- 이 와일드 카드는 욕심 많은 경우를 제외하고 0 또는 1 문자와 일치합니다. .이 와일드 카드는 욕심입니다. 그렇지 않으면 항상 다음 문자를 사용합니다. . 그러나 이름이 끝날 때 또는 다음 문자가.

  • *- 포함하여 0 개 이상의 문자 .와 일치합니다 (아래 예외 제외). 이 와일드 카드는 욕심이 없습니다. 후속 문자를 일치시키는 데 필요한만큼 또는 거의 일치합니다.

와일드 카드가 아닌 모든 문자는 몇 가지 특수한 경우를 제외하고 서로 일치해야합니다.

  • .-문자 자체가 일치하거나 더 이상 문자가 남아 있지 않으면 이름 끝과 일치하지 않습니다 (아무것도 없음) (참고-유효한 Windows 이름은으로 끝날 수 없습니다 .)

  • {space}-문자 자체가 일치하거나 더 이상 문자가 남아 있지 않으면 이름 끝과 일치하지 않습니다 (아무것도 없음) (참고-유효한 Windows 이름은으로 끝날 수 없습니다 {space})

  • *.마지막에 - 어떤 0 개 이상의 문자와 일치 제외 . 끝인는 .실제로 어떤 조합이 될 수 있습니다 .{space}한 마스크의 맨 마지막 문자이기 때문에 . 이것은 유일한 예외는 *단순히 문자의 설정과 일치하지 않습니다.

위의 규칙은 그렇게 복잡하지 않습니다. 그러나 상황을 혼란스럽게 만드는 중요한 규칙이 하나 더 있습니다. sourceMask는 긴 이름과 짧은 8.3 이름 (있는 경우)과 비교됩니다. 이 마지막 규칙은 마스크가 짧은 이름을 통해 일치하는 경우 항상 명확하지 않기 때문에 결과 해석이 매우 까다로울 수 있습니다.

RegEdit을 사용하여 NTFS 볼륨에서 짧은 8.3 이름 생성을 비활성화 할 수 있습니다.이 시점에서 파일 마스크 결과의 해석이 훨씬 간단 해집니다. 짧은 이름을 비활성화하기 전에 생성 된 짧은 이름은 그대로 유지됩니다.

대상

참고-엄격한 테스트를 수행하지는 않았지만 동일한 규칙이 COPY 명령의 대상 이름에도 적용됩니다.

targetMask는 새 이름을 지정합니다. 항상 전체 이름에 적용됩니다. sourceMask가 짧은 8.3 이름과 일치하더라도 targetMask는 짧은 8.3 이름에 적용되지 않습니다.

sourceMask에 와일드 카드가 있는지 여부는 targetMask에서 와일드 카드가 처리되는 방식에 영향을 미치지 않습니다.

다음 논의에서 - c모든 문자를 나타내는하지 *, ?또는.

targetMask는 역 추적없이 소스 이름에 대해 왼쪽에서 오른쪽으로 엄격하게 처리됩니다.

  • c-다음 문자가없고 대상 이름에 .추가 되는 한 소스 이름 내 위치를 향상시킵니다 c. (소스에 있던 문자를로 바꾸지 c만 절대로 바꾸지 않습니다 .)

  • ?- 소스 긴 이름에서 다음 문자와 일치하고 한 다음 문자가 아니므로 대상 이름에 추가합니다 . 다음 문자 인 경우 .또는 다음 어떤 문자가 결과와 현재에 추가되지 않습니다 소스 이름의 끝에있는 경우 소스 이름 내 위치는 변경되지 않습니다.

  • *at at targetMask-소스에서 대상으로 나머지 모든 문자를 추가합니다. 이미 소스의 끝에 있다면 아무 것도 수행하지 않습니다.

  • *c-현재 위치에서 마지막 발생 c(대소 문자 구분 욕심 일치) 까지 모든 소스 문자를 일치시키고 일치하는 문자 세트를 대상 이름에 추가합니다. c찾을 수 없으면 소스의 나머지 모든 문자가 추가되고 그 뒤에 c Windows 파일 패턴 일치가 대소 문자를 구분하는 유일한 상황입니다.

  • *.-현재 위치 에서 (욕심이 일치하는) 마지막 발생 까지 모든 소스 문자를 .일치시키고 일치하는 문자 세트를 대상 이름에 추가합니다. 를 .찾을 수 없으면 소스에서 남은 모든 문자가 추가 된 다음.

  • *?-소스에서 대상으로 나머지 모든 문자를 추가합니다. 이미 소스의 끝에 있다면 아무것도하지 않습니다.

  • .없이 *앞 - 스루 소스의 위치를 전진 최초 의 occurance을 .모든 문자를 복사하지 않고, 및 추가 .대상 이름. .소스에서 찾을 수 없으면 소스의 끝으로 진행 .하여 대상 이름에 추가 합니다.

targetMask이 소진 된 후, 후행 .{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 자까지 유지하기 위해 targetMask의 끝에 추가를 추가 할 수 있음 )

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 이상인 sourceMask ?는 항상 짧은 8.3 이름과 일치하므로 모든 파일과 일치합니다.

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


유용한 기발한 / 버그? 이름 접두사 삭제

이 수퍼 유저 게시물 에서는 슬래시 ( /)를 사용하여 파일 이름에서 선행 문자를 삭제하는 방법에 대해 설명합니다 . 각 문자를 삭제하려면 하나의 슬래시가 필요합니다. 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

엄청나게 정교하게!
Andriy M

13
이를 바탕으로, 마이크로 소프트는 그냥 "참조 사용에 대한 추가해야 superuser.com/a/475875 에서"를 REN /?.
efotinis 2016 년

4
@CAD-이 답변은 Simon이 내 요청에 따라 자신의 사이트에 포함한 100 % 원본 콘텐츠입니다. SS64 페이지의 맨 아래를 보면 Simon이이 작업에 대한 크레딧을 제공한다는 것을 알 수 있습니다.
dbenham

2
@ JacksOnF1re-새로운 정보 / 기술이 제 답변에 추가되었습니다. Copy of 애매한 슬래시 기술을 사용 하여 접두사를 실제로 삭제할 수 있습니다 .ren "Copy of *.txt" "////////*"
dbenham

4

exebook과 유사하게 소스 파일에서 대상 파일 이름을 가져 오기위한 C # 구현이 있습니다.

dbenham의 예제에서 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));

    }

내 예에서 실수에 대해 머리를 들어 주셔서 감사합니다. 문제를 해결하기 위해 답변을 편집했습니다.
dbenham

1

누군가가 이것을 유용하게 사용할 수 있습니다. 이 JavaScript 코드는 위의 dbenham의 답변을 기반으로합니다.

나는 시험하지 않았다 sourceMask매우하지만 targetMaskdbenham에 의해 주어진 모든 예제와 일치 않습니다.

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 * .TMP * .DOC 처리와 같은 와일드 카드 일치에 REN이 사용하는 함수를 복제합니다.
eoredson
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.