【问题标题】:How can I extrapolate a pattern from a collection of filenames?如何从文件名集合中推断出模式?
【发布时间】:2014-07-28 16:31:05
【问题描述】:

我想知道是否有一个众所周知的算法来推断文件名模式,给定一组示例文件名作为输入。采用以下示例文件名:

  ABC_348093423.csv
i.ABC_348097340.csv
  ABC_348099322.csv
i.GHI_348099324.csv
p.ABC_348101632.csv
  DEF_348101736.csv
p.ABC_348101633.csv
  ABC_348102548.csv

理想情况下,我希望在结果集中得到的模式类似于:

*.ABC_*.csv
*.DEF_*.csv
*.GHI_*.csv

即使像下面这样的结果值仍然是一个很好的起点:

i.ABC_348*.csv
p.ABC_348*.csv
...

我为什么需要这个?

我有一个现有的应用程序,用户可以在其中输入“文件掩码”来定义一个存储桶,以便将传入的输入文件分组到其中。根据每个文件掩码(按顺序)评估传入文件,如果文件与掩码匹配,则文件进入该文件掩码的存储桶......结束。

我想要实现的是,给定最后处理的 X 个文件名,向用户提供有关新文件掩码的建议。 它不一定是完美的。这只是一个用户辅助功能。

我使用的是什么语言?

我的应用程序是用 Java 编写的,因此任何可以执行此类功能的第三方 Java 库都是理想的解决方案。否则,如果有一个众所周知的算法可以解决这个问题,那么我可以自己实现它。

【问题讨论】:

  • 您在寻找正则表达式模式吗?
  • 分析字符串以识别模式几乎是一个独立的数学领域。不会有自动库来计算这个。
  • 离题:太宽泛对异地资源的建议
  • 不寻找 REGEX 模式,恰恰相反。给定一组输入,输出将是与输入匹配的模式。
  • 所以你基本上想将文件分组到集群中,然后找到一个可以区分集群的正则表达式模式。

标签: java pattern-matching extrapolation


【解决方案1】:

假设您只想根据常见子字符串建议通配符模式,您可以使用longest common substring algorithm 来计算所有常见子字符串,然后根据它们的长度和出现次数选择一些。这可以递归完成以找到更常见的子字符串。

此示例对 longest common substring 进行 2 次迭代并输出结果:

import java.util.*;

public class Main {

    private static String longestCommonSubstring(String S1, String S2)
    {
        int Start = 0;
        int Max = 0;
        for (int i = 0; i < S1.length(); i++)
        {
            for (int j = 0; j < S2.length(); j++)
            {
                int x = 0;
                while (S1.charAt(i + x) == S2.charAt(j + x))
                {
                    x++;
                    if (((i + x) >= S1.length()) || ((j + x) >= S2.length())) break;
                }
                if (x > Max)
                {
                    Max = x;
                    Start = i;
                }
            }
        }
        return S1.substring(Start, (Start + Max));
    }



    public static SortedMap<String,Integer> commonSubstrings(List<String> strings) {
        SortedMap<String,Integer> subs = new TreeMap<>();
        for (String str1: strings) {
            for (String str2: strings) {
                if (str1 != str2) {
                    String sub = longestCommonSubstring(str1,str2);
                    if (subs.containsKey(sub))
                        subs.put(sub,subs.get(sub)+1);
                    else
                        subs.put(sub,1);
                }
            }
        }

        return subs;
    }


    public static void main(String[] args) {
        List<String> filenames = Arrays.asList(
                "ABC_348093423.csv",
                "i.ABC_348097340.csv",
                "ABC_348099322.csv",
                "i.GHI_348099324.csv",
                "p.ABC_348101632.csv",
                "DEF_348101736.csv",
                "p.ABC_348101633.csv",
                "ABC_348102548.csv");

        Map<String,Integer> substrings = commonSubstrings(filenames);

        Map<String,Integer> subsubstrings = commonSubstrings(new ArrayList<>(substrings.keySet()));

        List<Map.Entry<String,Integer>> results = new ArrayList<>(subsubstrings.entrySet());
        Collections.sort(results, (a,b) -> a.getValue().compareTo(b.getValue()));

        for ( Map.Entry<String,Integer> s: results ) {
            System.out.println(s.getKey() + "\t" + s.getValue());
        }
    }
}

当然,这会遗漏所有文件名共有的较短子字符串,例如.csv

【讨论】:

    猜你喜欢
    • 2018-11-18
    • 1970-01-01
    • 2012-12-19
    • 2021-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多