文件智能排序(根据文件名称中的数字编号排序)

最近需要编写一个将一系列图片合并为一个webp动图的程序,遇到了一个文件排序的问题。

文件排序问题:

1.按照文件大小排序

2.按照文件修改时间排序

3.按照文件名称排序

这些排序操作都很简单,编程实现也很容易。

但是对于第3种排序,即按照文件名称排序,理解上其实存在一些歧义。

例如对于以下文件序列:

a10.txt
file9.txt
a9.txt
file8.txt
a8.txt
file11.txt
file7.txt
file10.txt
a11.txt

可以给出以下两种文件名称排序结果:

a8.txt
a9.txt
a10.txt
a11.txt
file7.txt
file8.txt
file9.txt
file10.txt
file11.txt
a10.txt
a11.txt
a8.txt
a9.txt
file10.txt
file11.txt
file7.txt
file8.txt
file9.txt

第二种结果很好理解,文件名按照字符的字典顺序进行排序,编程实现起来很简单。而第一种结果中,则提取了文件名中的数字,对数字部分按照数字大小来排序,其他字符部分按照字典序排序。

当文件名中的数字位数一致,即短位数用0补齐的情况下,两种排序方式是一致的,但是当文件名中的数字位数不一致时,两种排序的结果则有差异,在实际场景中,我们往往需要的是第一种结果。

第一种结果的排序方式如何编程实现呢?仔细一想,还有些麻烦,上例中,文件名只存在一个数字,如果文件名中存在多组数字呢,例如:

file9_9.txt
file9_10.txt
file9_11.txt
file10_9.txt
file10_10.txt
file10_11.txt

实现方式:

将文件名称按照普通字符、数字串拆分为一个字符串数组,在对两个文件名进行排序时,依次对比它们的字符串数组中的每一项,如果两者都是普通字符,则按照普通字符比较,如果两者都是数字串,则按照数字大小比较,否则认为数字串小于普通字符串,空字符串小于数组字符串。

编码实现:

两个类:

FileNameEntry.class:文件名中的一个字串,要么是一个不包含数字的普通字符串,要么是一个纯数字字符串。

FileName.class:FileNameEntry的集合。

package com.dancen.util.filesort;

import java.util.ArrayList;
import java.util.List;

import com.dancen.util.MyStringUtil;

/**
 * 
 * @author dancen
 *
 */
public class FileNameEntry implements Comparable<FileNameEntry>
{
	private String text;
	private long number;
	
	public static void main(String[] args)
	{
		List<FileNameEntry> entries = createFileNameEntries("a1");
		
		for(FileNameEntry entry : entries)
		{
			System.out.println(entry);
		}
	}
	
	public static List<FileNameEntry> createFileNameEntries(String fileName)
	{
		List<FileNameEntry> rs = null;
		
		if(null != fileName)
		{
			rs = new ArrayList<FileNameEntry>();
			StringBuilder textStringBuilder = new StringBuilder();
			StringBuilder numberStringBuilder = new StringBuilder();
			
			for(char c : fileName.toCharArray())
			{
				if(Character.isDigit(c))
				{
					if(0 != textStringBuilder.length())
					{
						String text = textStringBuilder.toString();
						textStringBuilder.delete(0, textStringBuilder.length());
						FileNameEntry fileNameEntry = new FileNameEntry(text, -1);
						rs.add(fileNameEntry);
					}
					
					numberStringBuilder.append(c);
				}
				else
				{
					if(0 != numberStringBuilder.length())
					{
						String text = numberStringBuilder.toString();
						numberStringBuilder.delete(0, numberStringBuilder.length());
						long number = MyStringUtil.parseLong(text, (long)-1);
						FileNameEntry fileNameEntry = new FileNameEntry(text, number);
						rs.add(fileNameEntry);
					}
					
					textStringBuilder.append(c);
				}
			}
			
			if(0 != textStringBuilder.length())
			{
				String text = textStringBuilder.toString();
				textStringBuilder.delete(0, textStringBuilder.length());
				FileNameEntry fileNameEntry = new FileNameEntry(text, -1);
				rs.add(fileNameEntry);
			}
			
			if(0 != numberStringBuilder.length())
			{
				String text = numberStringBuilder.toString();
				numberStringBuilder.delete(0, numberStringBuilder.length());
				long number = MyStringUtil.parseLong(text, (long)-1);
				FileNameEntry fileNameEntry = new FileNameEntry(text, number);
				rs.add(fileNameEntry);
			}
		}
		
		return rs;
	}
	
	private FileNameEntry(String text, long number)
	{
		this.setText(text);
		this.setNumber(number);
	}
	
	public String getText()
	{
		return this.text;
	}
	
	public long getNumber()
	{
		return this.number;
	}
	
	@Override
	public String toString()
	{
		return String.format("text=%s,number=%d", this.text, this.number);
	}
	
	@Override
	public int compareTo(FileNameEntry entry)
	{
		int rs = 0;
		
		if(null != entry)
		{
			String text = entry.getText();
			long number = entry.getNumber();
			
			if(0 <= this.number)
			{
				if(0 <= number)
				{
					rs = (int)(this.number - number);
				}
				else
				{
					rs = -1;
				}
			}
			else
			{
				if(0 <= number)
				{
					rs = 1;
				}
				else
				{
					rs = this.text.compareTo(text);
				}
			}
		}
		
		return rs;
	}
	
	private void setText(String text)
	{
		if(null == text)
		{
			throw new IllegalArgumentException("the text is null");
		}
		
		this.text = text;
	}
	
	private void setNumber(long number)
	{
		this.number = number;
	}
}
package com.dancen.util.filesort;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * 文件名称:支持智能排序
 * @author dancen
 *
 */
public class FileName implements Comparable<FileName>
{
	private String name;
	private List<FileNameEntry> entries;
	
	public static void main(String[] args)
	{
		List<FileName> fileNames = new ArrayList<FileName>();
		fileNames.add(new FileName("a"));
		fileNames.add(new FileName("005c"));
		fileNames.add(new FileName("c"));
		fileNames.add(new FileName("b100"));
		fileNames.add(new FileName("b9"));
		fileNames.add(new FileName("05c"));
		fileNames.add(new FileName("004c"));
		fileNames.add(new FileName("a002"));
		fileNames.add(new FileName("b10"));
		fileNames.add(new FileName("a001"));
		fileNames.add(new FileName("a9_1"));
		fileNames.add(new FileName("a008_5"));
		fileNames.add(new FileName("a000"));
		fileNames.add(new FileName("b"));
		fileNames.add(new FileName("d"));
		fileNames.add(new FileName("b1000"));
		fileNames.add(new FileName("a008_4"));
		fileNames.add(new FileName("a008_10"));
		fileNames.add(new FileName("a008_10_1"));
		fileNames.add(new FileName("a008_10_10"));
		fileNames.add(new FileName("a9_11"));
		fileNames.add(new FileName("2e3"));
		fileNames.add(new FileName("2e4"));
		fileNames.add(new FileName("3e1"));
		fileNames.add(new FileName("f"));
		fileNames.add(new FileName("3e5"));
		fileNames.add(new FileName("3e3"));
		fileNames.add(new FileName("3e20"));
		Collections.sort(fileNames);
		
		for(FileName fileName : fileNames)
		{
			System.out.println(fileName.getName());
		}
	}
	
	public FileName(String name)
	{
		this.setName(name);
		this.entries = FileNameEntry.createFileNameEntries(this.name);
	}
	
	public String getName()
	{
		return this.name;
	}
	
	public List<FileNameEntry> getEntries()
	{
		return new ArrayList<FileNameEntry>(this.entries);
	}
	
	@Override
	public int compareTo(FileName fileName)
	{
		int rs = 0;
		
		if(null != fileName)
		{
			List<FileNameEntry> entries = fileName.getEntries();
			int size = Math.min(this.entries.size(), entries.size());
			
			for(int i = 0; i < size; i++)
			{
				rs = this.entries.get(i).compareTo(entries.get(i));
				
				if(0 != rs)
				{
					break;
				}
			}
			
			if(0 == rs)
			{
				rs = this.entries.size() - entries.size();
			}
		}
		
		return rs;
	}
	
	private void setName(String name)
	{
		if(null == name)
		{
			throw new IllegalArgumentException("the name is null");
		}
		
		this.name = name.trim();
	}
}

 

代码中的输出结果:

2e3
2e4
3e1
3e3
3e5
3e20
004c
005c
05c
a
a000
a001
a002
a008_4
a008_5
a008_10
a008_10_1
a008_10_10
a9_1
a9_11
b
b9
b10
b100
b1000
c
d
f

 

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值