记一次windows重命名

0. 起因

    最近龙珠又更新了,不知道各位小伙伴知不知道,今日一气之下,将所有更新下载了下来,可是问题来了,下下来的文件,名字中都会有网站的信息,如:“[龙珠超][40][红旅首发www.hltm.cc][GB][720P][MP4][异域字幕组].mp4”,而小生只想要这样的命名:“龙珠超-01.mp4”。
    于是乎,就有了如下问题:如何批量重命名呢?

    环境:win10_x64, git bash(windows cmd太难用了), sublime text 3

    过程很清晰了:列出所有mp4文件来,找到它是第几集,把名字拼起来,改名,完毕!
    那就开工吧!

1. Python

python脚本似乎很好写呢,那就试试呗
# -*- coding: utf8 -*-
import os
import os.path
import re
import sys

usage = '''\
    Usage: newname\
'''
if len(sys.argv) < 2:
    print usage
    exit(1)

# ---------------------------

FILE_NAME = ' '.join(sys.argv[1:]) # Dragon ball super 龙珠超
FILE_TYPE = '.mp4'

pwd = os.getcwd()
print 'pwd is:', pwd

files = [file for file in os.listdir(pwd) if os.path.isfile(file) and os.path.splitext(file)[1] == FILE_TYPE]

regexp = ur'[0-4][0-9]'

fails = []

for file in files:
    num = re.search(regexp, file)
    if num:
        newname = "%s-%s%s" % (FILE_NAME, num.group(), FILE_TYPE)
        print "%s: %s --> %s" % (num.group(), file, newname)
        os.rename(file, newname)
    else:
        fails.append(file)

if not fails:
    exit(0)

print "\n**************** fails ****************"
for file in fails:
    print file

exit(1)
运行:python rename.py 龙珠超
    这是最后的样子了,之前写的时候,小生直接把“龙珠超”写在了代码里,python会报windows errno: 123的错误,但把encoding改成cp936又会报无法识别汉字的问题,最后只能将就把“龙珠超”当参数传进来了。

2. PHP

php是世界上最好的语言,伟哉我大php!!!
如上,用python会因为编码问题而困扰,所以就想到了用世界上最好的编程语言试试:
<?php

define("FILE_NAME", "龙珠超");
define("FILE_EXT", "mp4");

$pwd = getcwd();
if (!$pwd) {
    echo "Getcwd error!";
    exit(1);
}
echo "pwd is: $pwd\n";

$handler = opendir($pwd);
if ($handler === false) {
    echo "Opendir error!";
    exit(1);
}

$fails = [];
while ($file = readdir($handler)) {
    if ($file === false) {
        echo "Read dir error!";
        exit(1);
    }
    if (pathinfo($file, PATHINFO_EXTENSION) != FILE_EXT) {
        continue;
    }
    preg_match('/[0-4][0-9]/', $file, $num);
    if (count($num) == 0) {
        $fails[] = $file;
        continue;
    }
    $newname = FILE_NAME . "-$num[0]." . FILE_EXT;
    echo "$file --> $newname\n";
    if (rename($file, $newname) == false) {
        $fails[] = $file;
    }
}

closedir($handler);

if ($fails) {
    echo "\n" . '************ fails ************' . "\n";
    foreach ($fails as $file) {
        echo "$file\n";
    }
    exit(1);
}
运行:php rename.php
很不幸,又报windows 123错了,郁闷了……

3. Golang

上面两个都跪了,用Google的语言试试吧
package main

import (
    "fmt"
    "io/ioutil"
    "log"
    "os"
    "path/filepath"
    "regexp"
)

const (
    FILE_NAME = "龙珠超"
    FILE_EXT  = ".mp4"
)

func main() {
    pwd, err := os.Getwd()
    if err != nil {
        log.Fatal(err)
    }

    fileinfos, err := ioutil.ReadDir(pwd)
    if err != nil {
        log.Fatal(err)
    }

    re := regexp.MustCompile(`[0-4][0-9]`)
    fails := []string{}
    for _, info := range fileinfos {
        if info.IsDir() {
            continue
        }
        if filepath.Ext(info.Name()) != FILE_EXT {
            continue
        }

        newname := fmt.Sprintf("%v-%v%v", FILE_NAME, re.FindString(info.Name()), FILE_EXT)
        fmt.Printf("%v --> %v\n", info.Name(), newname)
        if err := os.Rename(info.Name(), newname); err != nil {
            log.Println(err)
            fails = append(fails, info.Name())
        }
    }

    if len(fails) > 0 {
        fmt.Println("****************** fails ******************")
        for _, file := range fails {
            fmt.Println(file)
        }
        os.Exit(1)
    }
}
运行:go run rename.go
    哈,一次就过,Google语言确实牛逼!

4. C

想想都写了这么多了,为啥不试试万能的C语言呢?
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

#define FILE_NAME   "龙珠超"
#define FILE_EXT    ".mp4"

#define Free(ptr) if(ptr){free(ptr);ptr=NULL;}

int endwith(const char* str, const char* end) {
    size_t l_str = strlen(str);
    size_t l_end = strlen(end);
    if (l_str < l_end) {
        return 0;
    }

    return !strcmp(str+(l_str-l_end), end);
}

typedef struct {
    int start, end;
} range_t;

int find_num_seq(const char* src, size_t size, size_t n, range_t ranges[], size_t end) {
    range_t range;
    size_t i, cnt, seq_size, len = strlen(src);
    if (end > len) {
        end = len;
    }

    for (i = cnt = seq_size = 0; i < end && cnt < n; i++) {
        if (isdigit(src[i])) {
            if (seq_size == 0) {
                range.start = i;
            }
            range.end = i+1;
            seq_size++;
        } else {
            if (seq_size == size) {
                ranges[cnt].start = range.start;
                ranges[cnt].end = range.end;
                cnt++;
            }
            seq_size = 0;
        }
    }

    return cnt == n;
}

int main() {
    char*          pwd  = NULL;
    DIR*           dir  = NULL;
    struct dirent* file = NULL;
    int            err  = 0;

    if ((pwd = getcwd(NULL, _MAX_PATH)) == NULL) {
        err = errno;
        printf("getcwd error!\n");
        goto END;
    }
    printf("pwd: %s\n", pwd);

    if ((dir = opendir(pwd)) == NULL) {
        err = errno;
        printf("opendir error!\n");
        goto END;
    }

    while (1) {
        if ((file = readdir(dir)) == NULL) {
            err = errno;
            if (err) {
                printf("readdir error!\n");
                goto END;
            } else {
                break;
            }
        }
        if (endwith(file->d_name, FILE_EXT)) {
            int i;
            range_t range;
            if (find_num_seq(file->d_name, 2, 1, &range, -1)) {
                char* newname = NULL;
                char* num = (char*)malloc((range.end-range.start+1) * sizeof(char));
                if (num == NULL) {
                    err = errno;
                    printf("malloc error!\n");
                    goto END;
                }
                memset(num, 0, sizeof(num));
                memcpy(num, file->d_name+range.start, range.end-range.start);

                newname = (char*)malloc((strlen(FILE_NAME) + strlen(num) + strlen(FILE_EXT) + 8) * sizeof(char));
                memset(newname, 0, sizeof(newname));
                sprintf(newname, "%s-%s%s", FILE_NAME, num, FILE_EXT);
                printf("%s --> %s\n", file->d_name, newname);
                if (rename(file->d_name, newname) != 0) {
                    err = errno;
                    Free(newname);
                    Free(num);
                    printf("rename error!\n");
                    goto END;
                }
                Free(newname);
                Free(num);
            } else {
                printf("fail: %s\n", file->d_name);
            }
        }
        Free(file);
    }

END:
    if (dir != NULL) {
        closedir(dir);
        dir = NULL;
    }
    Free(pwd);
    if (err) {
        printf("errno[%d]: %s\n", err, strerror(err));
    }
    return err;
}
运行:gcc rename.c -o rename && ./rename
    也报错了,与众不同的是,报的errno是22 Invalid argument。这就不应该了吧,c这么万能的语言怎么能解决不了这种小儿科呢?

    肯定是哪里出错了!可是是哪里呢?我试着用记事本打开rename.c并保存居ansi编码,然后再运行,OK了!!!原来是sublime保存utf8编码不适用于windows!!!

那来验证一下:

5. Java

import java.io.File;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Rename {
    private static final String FILE_NAME = "龙珠超"; // Dragon ball super
    private static final String FILE_EXT  = ".mp4";

    private static String getExt(String file) {
        if (file.lastIndexOf(".") > 0 && file.lastIndexOf(".") < file.length()-1) {
            return file.substring(file.lastIndexOf("."));
        }
        return "";
    }

    public static void main(String[] args) {
        String pwd = System.getProperty("user.dir");
        File[] files = (new File(pwd)).listFiles();
        ArrayList<String> fails = new ArrayList<String>();
        Pattern pattern = Pattern.compile("[0-4][0-9]");

        for (File file: files) {
            if (file.isFile() && getExt(file.getName()).equals(Rename.FILE_EXT)) {
                System.out.println(file.getName());
                Matcher matcher = pattern.matcher(file.getName());
                if (matcher.find()) {
                    String newname = Rename.FILE_NAME + "-" + matcher.group() + Rename.FILE_EXT;
                    System.out.format("%s --> %s", file.getName(), newname);
                    try {
                        file.renameTo(new File(newname));
                    } catch (Exception e) {
                        e.printStackTrace();
                        fails.add(file.getName());
                    }
                } else {
                    fails.add(file.getName());
                }
            }
        }

        if (fails.size() > 0) {
            System.err.println("************* fails *************");
            for (String file: fails) {
                System.err.println(file);
            }
            System.exit(1);
        }
    }
}
运行: javac Rename.java && java Rename
    在保存为utf8时编译通不过,改为ansi时正常运行。

6. Bash

细细想来,直接写个bash脚本不就OK了吗?为啥要启用编程语言呢?
#/bin/bash

FILE_NAME="龙珠超"
FILE_EXT="mp4"

files=(`ls`)

for file in ${files[@]}; do
    if [[ "${file##*.}" = "$FILE_EXT" ]]; then
        num=`expr match "$file" '.*\([0-4][0-9]\).*'`
        newname="${FILE_NAME}-${num}.${FILE_EXT}"
        echo $file "-->" $newname
        mv "$file" "$newname"
    fi
done
运行:./rename.sh
    一切OK!!!

俗话说,天做孽,犹可恕,自做孽,不可活呀!


反思:
  1. 为什么一开始想到的不是bash脚本,而是用python这类脚本去解决呢?
    处理什么样的问题,用什么样的工具,用最简单,最切合实际的工具去解决它最擅长的领域。Python也许还有几分道理,但如PHP本是用来解决网站问题的,Golang是解决服务器问题的,C用的最没道理,因为一个这种小问题,完全找不到用它的理由。
    另外,亦可能是因为windows平台,直接就掠过bash脚本(小生不会用bat),没意识到一直用的是git bash。

  2. windows的cp936编码
    直接导致Sublime下岗,Python罢工,除Golang和Bash之外要指定保存编码格式为ansi。之后再处理类似问题时须注意。


庆祝一下所有的文件命名格式都对啦!哈哈哈哈

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值