如果在文件夹中找到图片,则写入文件

时间:2013-10-29 00:03:42

标签: regex bash shell csv

我有一个csv文件,在第一列中有一个由数字和大写字母组成的产品代码列表,在第二列可用空间中用于图片名称第一列的产品。

我还有一个包含几乎所有图片的文件夹,但图片的代码是产品代码的子字符串(编辑:前缀)。图片和产品之间的匹配是一对多,因此一个产品共享相同的图片。 例如:

3234P3001 and 3234P3002 have the same picture 3234P30

我需要创建一个shell脚本,扫描csv文件中的代码列表,如果有一个图片名称是此代码的子字符串,则会在第二列中写入该图片的名称

这是我的第一个大项目,我没有数据操作方面的经验。

查找图片之间的最大子字符串是我产品的图片。

3 个答案:

答案 0 :(得分:2)

您可以动态组装sed脚本,替换现有的每个图像文件

#!/bin/bash

sed -i -f <(
    find images/ -type f -name '*.jpg' | LANG=C sort -r | 
    while read imagename
    do
        basename=$(basename "$imagename" .jpg)
        echo "s#^\\($(printf "%q" "$basename")[^;]*;\\);#\\1$imagename;#"
    done) "$@"

注意:

  • 脚本是动态编译的sed脚本
  • 我对文件名进行降序排序(因此具有公共前缀的最长图像名称将被视为首先
  • 我只扫描一次images目录(为了提高性能,还能够创建可预测的结果)
  • 已更新:现在,该脚本实际上处理了具有公共前缀的图像(例如3234.png以及3234P30.png)。最长的匹配将占上风 - 因为sort -r步骤)

示例:对于输入文件

3234P3001;;aa
3234P3002;;bb

执行script.sh input将导致

3234P3001;/tmp/images/3234P30.png;aa
3234P3002;/tmp/images/3234P30.png;bb

答案 1 :(得分:2)

这几乎可以满足您的需求。

假设您的产品代码存储在名为products.csv的文件中,如果您将以下代码保存在名为“go”的文件中,那么请执行

chmod +x go
./go < products.csv

可能需要一点点调整......

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Cwd;

my $Debug=1;        # Set to 0 to turn off debug output
my $photosdir="/tmp";   # Or wherever your photos are

# Go to photos directory and load names of all JPEGs into array @photos
chdir $photosdir or die "Unable to chdir() to $photosdir\n";
my @photos=<*.jpg>;

# Debug - output photo filenames
print Dumper @photos if $Debug;

# Read product codes from our stdin
while(<>){
   chomp;
   my $product = $_ ;
   $product =~ s/;.*//;

   print "Finding photo for product: $product\n" if $Debug;

   # Run through all photo filenames and find longest match
   my $longestmatch=0;
   my $bestimage="<NONE>";

   foreach my $photo (@photos){
         # Strip extension off photo name
         $photo =~ s/\.jpg//;

         print "Assessing photo $photo\n" if $Debug;

         if($product =~ m/(^$photo)/ ){
            my $matchlength = length($&);
            if($matchlength > $longestmatch){
               print "Best match so far: $photo, ($matchlength characters)\n" if $Debug;
               $longestmatch = $matchlength;
               $bestimage = $photo . ".jpg";
            }
         }
   }
   print "$product,$bestimage\n";
}

实际上,你可以通过哈希更优雅,更快地完成它。在找到最长的匹配项之前,不要查看成千上万张照片中的每一张照片,只需尝试查看产品的前n个字母是否在哈希中,如果没有尝试前n-1个字母,那么前n-2个字母, 像这样。对于大量的产品和照片,它应该运行得更快。

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;
use Cwd;

my $Debug=1;        # Set to 0 to turn off debug output
my $photosdir="/tmp";   # Or wherever your photos are

# Go to photos directory and load names of all JPEGs into array @filenames
chdir $photosdir or die "Unable to chdir() to $photosdir\n";
my @filenames=<*.jpg>;

# Now create hash of photonames without ".jpg" extension
my %photos;
for my $photo (@filenames){
   $photo =~ s/\.jpg//;
   # So if there was a file "xyz.jpg", $photos{"xyz"} will be defined
   $photos{$photo}=1;
}

# Debug - output photo filenames
print Dumper \%photos if $Debug;

# Read product codes from our stdin
while(<>){
   chomp;   # remove end of line
   my ($product,$field2,$field3) = split ";";

   print "Finding photo for product: $product\n" if $Debug;

   my $bestimage="<NONE>";  # Preset and overwrite if better one found

   # Keep removing last character of product till it matches a photo
   for(my $i=length($product);$i;$i--){
      my $short = substr($product,0,$i);
      print "Trying $short\n" if $Debug;
      if(defined($photos{$short})){
         $bestimage = $short . ".jpg";
         last;
      }
   }
   print "$product;$bestimage;$field3\n";
}

答案 2 :(得分:0)

由于您尚未指定问题所在或您尝试过的内容,因此这里有一些伪代码可帮助您入门:

foreach line in csvfile {
   code = get first column(line)
   foreach filename in folder {
      if(filename is a substring of code) { 
         //match!
         write to file ("code, filename")
         break;
      }
   }
}