お知らせ

  • 利用規約を守って投稿してください。また、よくある質問および投稿の手引きも参照してください。
  • メッセージの投稿にはアカウントが必要です。未登録の方は、ユーザ登録ページからアカウントを作成することができます。

#1 2011-09-18 06:58:58

seitakatxt
新しいメンバ
登録日: 2011-09-18

複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

初めてフォーラムを利用します。

電子書籍の作成のために、ファイルの一括処理をしたいと思っています。

元データは、
ファイル名:「ランダムな英数字.php」
ファイルの中身:htmlタグのついたテキストデータ
700個くらいあります。

ファイルの中には、
 <td class="basetxt">Jan-26-2009</td>
という感じで、決まったタグに囲われた日付があります。なお、日付は重複していません。また、「basetxt」というclassは同一ファイル内には一度しかでてきません。
この日付部分を抜き出して、 「20090126.xhtml」 というようなタイトルに変更したいのですが、やり方がわかりません。

拡張子の一括変更は自力で何とかできそうです。

また、
$ grep -r '<td class="basetxt">.*</td>' ./*
とコマンドを打ち込んで、
./1573.php:<td class="basetxt">Jan-26-2009</td>
という結果が帰ってくるところはでき、それをおそらく、パイプでつないで、renameして、正規表現をつかって日付の形式を置換すればいいのではないかと思うのですが、力及ばず、知恵たらず。。。

アドバイス、よろしくおねがいします!

オフライン

 

#2 2011-09-18 08:24:03

funatogawa
メンバ
From: 関東
登録日: 2009-02-01

Re: 複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

file名を変更するときは普通は「mv」コマンドを使いますが、
こんなのはどうでしょう。
Linux Tips 複数ファイルのファイル名を一括変換する@kazmax.zpp.jp

オフライン

 

#3 2011-09-18 09:23:29

himajin216
メンバ
登録日: 2011-09-18

Re: 複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

暇人が朝飯前にperlで作ってみました。

1.下記リストをgeditなどにコピーします。
2.エディタで4行目の
     my $target_dir = '/home/USER_NAME/test';
   の USER_NAME をあなたのユーザー名に変えます。
3.、適当なディレクトリに、保存します。
    (一応 USER_NAME/perl/etc に保存するものとします)
4.ファイル名は一応 ch_filename.pl にしていますが、変更しても構いません。
3.Nautilus でそのファイルを右クリックし、「プロパティ」→「アクセス権」で「プログラムとして実行できる」にチェックをつけます。
5.USER_NAME/test ディレクトリに変換対象ファイル(s)をコピー。
    元ファイルは必ず別に保管!
6.端末を開いて、 cd perl/etc と入力。(違うディレクトリに保存したならそこへ)
7.端末で  ./ch_filename.pl を実行。

#!/usr/bin/perl
# filename = 'ch_filename.pl';

my $target_dir = '/home/USER_NAME/test';  #変換対象ファイルを置いたディレクトリ
chdir $target_dir;                                          #念のためフルパスで(最後の / は不要)

#@files にファイル一覧リストを得る
my @files = get_filelist("$target_dir");


for $file(@files){
    my $line = '';
    my $date = '';

    open IN,"$file";
    while( $line = <IN> ){
        if ($line =~ m/"basetxt">(.*)<\/td>/i){
            $date = $1;
            last;
        }
    } #wend
    close IN;

    if ($date ne ''){
        rename_to_date($file,$date);
    }
}

exit;

sub rename_to_date{
    my ($file,$date) = @_;
   
    my ($mm,$dd,$yy) = split(/-/,$date);
    if ($mm =~ m/jan/i){
        $mm = 1;
    }elsif($mm =~ m/feb/i){
        $mm = 2;
    }elsif($mm =~ m/mar/i){
        $mm = 3;
    }elsif($mm =~ m/apr/i){
        $mm = 4;
    }elsif($mm =~ m/may/i){
        $mm = 5;
    }elsif($mm =~ m/jun/i){
        $mm = 6;
    }elsif($mm =~ m/jul/i){
        $mm = 7;
    }elsif($mm =~ m/aug/i){
        $mm = 8;
    }elsif($mm =~ m/sep/i){
        $mm = 9;
    }elsif($mm =~ m/oct/i){
        $mm = 10;
    }elsif($mm =~ m/nov/i){
        $mm = 11;
    }elsif($mm =~ m/dec/i){
        $mm = 12;
    }
    my $new_file = sprintf("%4d%02d%02d.xhtml",$yy,$mm,$dd);
   
    rename $file,$new_file;
}


sub get_filelist{
    my $dir = $_[0];
    my (@files,$file);
   
    if (-e $dir){
        opendir(DIR,$dir) || die "Can't open '$dir'.";
        while( $file = readdir DIR){
            #自分自身と上位ディレクトリを除く
            if ( ($file eq '.') or ($file eq '..') ){
                next;
            }

            push @files, "$dir/$file";

        }
        closedir DIR;
    }

    #返す前にソートする
    @files = sort(@files);
   
    return (@files);
}

オフライン

 

#4 2011-09-18 16:28:57

seitakatxt
新しいメンバ
登録日: 2011-09-18

Re: 複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

funatogawa による投稿:

file名を変更するときは普通は「mv」コマンドを使いますが、
こんなのはどうでしょう。
Linux Tips 複数ファイルのファイル名を一括変換する@kazmax.zpp.jp

funatogawaさん、どうもありがとうございました。参考にさせていただきました。
「rename」は頻繁に使いそうなので、頑張ってマスターします!

オフライン

 

#5 2011-09-18 18:04:34

hir0
メンバ
登録日: 2008-09-28

Re: 複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

正規表現をつかって日付の形式を置換すればいいのではないかと思うのですが、力及ばず、知恵たらず。。。

アドバイス、よろしくおねがいします!

今回の様な場合のLinuxコマンドを使用した場合のアプローチ方法の例です。

コード:

mv ./1573.php $(grep '<td class="basetxt">' ./1573.php|cut -f 2 -d '>'|cut -f 1 -d '<')

上記はファイル単体での操作ですが、複数のファイルを条件別に操作するにはシェルスクリプトを使用して条件式やループを使用しなければいけません。
実際には違うファイルがディレクトリに在った時等の例外処理も必要ですが省略しています。
Linuxコマンドの使用例なのでスペルミスや動作チェックは行っていません。

今後も似たような作業が必要になるようでしたら自力解決の参考にしてください。

内容が #3 と重複しますので概略を書きます。




変数dirにターゲットファイルのパスを入れます。

dir= '/hoge/hoge/hoge'

変数kazu に変更するファイル数を入れます。

kazu=$(ls $dir | wc -l)

変数にターゲットファイルの名前を入れます

set $(ls $dir)

・変数kazu の数だけfor文を用いて処理を繰り返します。
・$1~$n にはターゲットファイル名が入っています。
・hoge にJan-26-2009等が入ります。
・year,month,day にそれぞれ2009,Jan,26が入ります。
・cae文でmonth の英語表記を数字に変換します。
・hoge にyear,month,dayを入れます。
・mv コマンドでファイル名を書き換えます。
・for文の変数iに1が加算されて2になります。
・$2に格納されたファイル名に同じ処理がされます。
・変数kazu(ファイルの数)だけ処理を繰り返し終了します。
・ファイルを日付順に並べ替えます。

for (( i = 1 ; i < $kazu ;i ++ ))
do
  hoge=  $(grep '<td class="basetxt">' $dir'/'$i |cut -f 2 -d '>'|cut -f 1 -d '<')
  year= $(cut hoge -f 3 -d '-')
  month= $(cut hoge -f 1 -d '-')
  day= $(cut hoge -f 2 -d '-')
  case $month in
    Jan) monsh=01
         ;;
    Feb) monsh=02
         ;;
    Mar) monsh=03
         ;;
    Apr) monsh=04
         ;;
    May) monsh=05
         ;;
    Jun) monsh=06
         ;;
    Jul) monsh=07
         ;;
    Aug) monsh=08
         ;;
    Sep) monsh=09
         ;;
    Oct) monsh=01
         ;;
    Jan) monsh=10
         ;;
    Nov) monsh=11
         ;;   
    Dec) month=12
         ;;
  esac
  hoge=$year $month $day
  mv $dir'/'$i $hoge
done

オフライン

 

#6 2011-09-18 18:24:38

seitakatxt
新しいメンバ
登録日: 2011-09-18

Re: 複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

himajin216 による投稿:

暇人が朝飯前にperlで作ってみました。

himajin216さん、朝ごはん前にありがとうございました!

やってみました。・・・できた、しかも一瞬で、すごい!
スクリプトを書けるようになれば、こんなふうにできてしまうのですね。

が、元ディレクトリよりファイルの数が少ない。。。
最初の質問の「なお、日付は重複していません。」の部分が間違っていたようです。日付が重複していた場合には一つだけしかファイルが残っていませんでした。
日付のあとに元のファイル名(「ランダムな英数字.php」の拡張子を省いた部分)を残せばうまくいきそうに思います。

ほぼ一からですが、Perlの勉強もやってみようと思います。

オフライン

 

#7 2011-09-18 18:50:32

seitakatxt
新しいメンバ
登録日: 2011-09-18

Re: 複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

hir0 による投稿:

正規表現をつかって日付の形式を置換すればいいのではないかと思うのですが、力及ばず、知恵たらず。。。

アドバイス、よろしくおねがいします!

今回の様な場合のLinuxコマンドを使用した場合のアプローチ方法の例です。

hir0さん、ありがとうございます!連休中にやってみます!

シェルスクリプト、条件式、ループ、ですね。
自分のやりたいことの難易度、なにを勉強したら良いかがわからなくて立ち往生していました。
フォーラムに投稿してみて本当に良かったと思いました。

結果、ご報告させていただきます。

オフライン

 

#8 2011-09-18 19:21:32

himajin216
メンバ
登録日: 2011-09-18

Re: 複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

seitakatxt による投稿:

日付のあとに元のファイル名(「ランダムな英数字.php」の拡張子を省いた部分)を残せばうまくいきそうに思います。

暇人が夕飯前に改造しました。

60行の
    my $new_file = sprintf("%4d%02d%02d.xhtml",$yy,$mm,$dd);

    $file =~ m/\/([\w\d]*)\.php/i;
    my $stem = $1;
    my $new_file = sprintf("%4d%02d%02d_$stem.xhtml",$yy,$mm,$dd);
の3行にしてください。

なお、あくまで使い捨てのスクリプトということで、エラー処理やこまかな対象ファイル名の検索などをしていませんので、まだ必要があれば言ってください。

オフライン

 

#9 2011-09-18 19:54:07

STGSAGWAN
ゲスト

Re: 複数のファイルから文字列を抽出して、それをファイル名に反映させるには?

seitakatxtさん

私ならば、対象ファイルをfindで絞り、-execで変換プログラムに渡します。

この場合の変換プログラムは、何かのスクリプト言語で作成し、
1. ファイルパスを引数で受け取る
2. ファイル内の日付文字列を取得
3. 日付文字列をyyyymmddに変換
4. リネーム後のファイルパスを作成
5. 実際にファイルをリネーム。
するものです。

以下、実装サンプルです。

コード:

$ find /path/to/dir/ -type f -name '*.php' -exec /path/to/cnv.py {} \;

cnv.py  (python 2.6)

コード:

#!/usr/bin/env python
import sys
import os.path
import re
import datetime
filepath = sys.argv[1]
p = re.compile(r'<td class="basetxt">(?P<datestr>.*)</td>')
for line in open(filepath, "r"):
    m = p.match(line)
    if m != None:
        datestr = m.group('datestr')
        break
filename_cnv = datetime.datetime.strptime(datestr, "%b-%d-%Y").strftime("%Y%m%d") + ".xhtml"
filepath_cnv = os.path.join(os.path.dirname(filepath), filename_cnv)
print filepath, datestr, filepath_cnv
# os.rename(filepath, filepath_cnv)

※実際にリネームするには、最終行のコメントを外す。

もう解決しているようですが、こういうのもあるという事で、参考になれば。

 

Board footer

Powered by FluxBB