字符串匹配模式

时间:2018-04-24 15:57:24

标签: java string algorithm data-structures

我有两个模式a.{var1}.{var2}b.{var1}.{var2}的字符串。

如果第一个字符串中的var1与第二个字符串中的var1相同,则匹配两个字符串,并且第一个字符串中的var2与第二个字符串中的var2相同。

变量可以是a.{var1}.{var2}b.{var2}.{var1}等任何顺序。

如何有效地匹配两个字符串?

示例1:

String pattern1 = "1.{var1}";
String pattern2 = "2.{var1}";

//Match True = (1.111,2.111)
//Match False = (1.121,2.111)

示例2:

String pattern1 = "1.{var1}.{var2}";
String pattern2 = "2.{var1}.{var2}";

//Match True = (1.11.22,2.11.22)
//Match False = (1.11.22,2.111.22)

示例3:

String pattern1 = "1.{var1}.{var2}";
String pattern2 = "2.{var2}.{var1}";

//Match True = (1.22.11,2.11.22)
//Match False = (1.11.22,2.111.22)

那么匹配这两个字符串的最佳方式是什么?

我想匹配这两个字符串,以确定它们是否与提到的模式有关 将此问题扩展为一组字符串,即Set A字符串必须与Set B中的字符串匹配。最后,必须形成满足该匹配算法的字符串对。当匹配Set A到Set B中的所有字符串时,模式将保持不变。

6 个答案:

答案 0 :(得分:2)

这可能不是最有效的方法,但它确实为您提供了预期的输出。

01/05:Ole在comments ::

中指出错误后更新了代码
private boolean compareStr(String a, String b) {
    ArrayList<String> aList = new 
    ArrayList<String>(Arrays.asList(a.split("\\.")));
    ArrayList<String> bList = new ArrayList<String>(Arrays.asList(b.split("\\.")));
    bList.remove(0);
    aList.remove(0);

    if(aList.size() != bList.size())
            return false;

    boolean aMatchFlag = false;
    for(int i=0; i< aList.size(); i++){
        if (!bList.contains(aList.get(i))) {
            return false;
        }
    }
    aMatchFlag = true;
    System.out.println("All elements of A are present in B");
    boolean bMatchFlag = false;
    for(int i=0; i< bList.size(); i++){
        if (!aList.contains(bList.get(i))) {
            return false;
        }
    }
    bMatchFlag = true;
    System.out.println("All elements of B are present in A");

    if(aMatchFlag && bMatchFlag)
            return true;
    else
            return false;
}

对于那些也在寻找代码性能的人

Input:1.11.11, 2.11.11.11
Compilation time: 1.45 sec, absolute running time: 0.24 sec, cpu time: 0.26 sec, memory peak: 18 Mb, absolute service time: 1,7 sec

Input:1.11.11, 2.11.22
Compilation time: 1.25 sec, absolute running time: 0.24 sec, cpu time: 0.23 sec, memory peak: 18 Mb, absolute service time: 1,49 sec

Input:1.11.2, 2.11.22
Compilation time: 1.34 sec, absolute running time: 0.24 sec, cpu time: 0.24 sec, memory peak: 18 Mb, absolute service time: 1,58 sec


Input:1.11.2, 2.11.111
Compilation time: 1.65 sec, absolute running time: 0.28 sec, cpu time: 0.32 sec, memory peak: 18 Mb, absolute service time: 1,94 sec

答案 1 :(得分:1)

您可以使用以下String类方法:

boolean regionMatches(int toffset, String other, int ooffset, int len)

测试此字符串的指定区域是否与String参数的指定区域匹配。 Region的长度为len,从此字符串的索引toffset开始,另一个字符串的ooffset开始。

忽略大小写:

boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len)

更多信息:https://docs.oracle.com/javase/tutorial/java/data/comparestrings.html

或尝试从一个字符串动态创建一个正则表达式模式并与其他字符串进行比较......虽然不是一种有效的方法

答案 2 :(得分:0)

在生成的数组元素上使用select t1.name, case when t1.[address] is not null and len(t1.[address]) > 0 then t1.[address] else t2.[address] end as [address], t1.value, t1.[date] from test t1 left join test t2 on t2.id = (select top 1 id from test where [date] >= t1.[date] and id <> t1.id) 然后String.split(),分别处理这三种情况。

分割后,首先检查结果数组是否具有相同的长度(如果不匹配)。如果需要,还可以使用String.equals()检查第一个元素是String.equals()"1"。然后分支长度是2还是3.如果长度是2,检查匹配是否与示例1中的匹配一样;再次对数组元素使用"2"。如果长度为3,则需要根据两个示例2和3检查变量部分的两个顺序。

请记住,String.equals()的参数是正则表达式,并且点在正则表达式中具有特殊含义。因此,您需要使用String.split(),而不是.split("\\.")

它也应该跑得很快。但是,在您知道需要更好的性能之前,请不要开始优化。可读性是王道。

快乐的编码。

编辑:假设您有时间编写自己的解决方案,我会向我展示灵感,并与您的解决方案进行比较(如果您愿意,可以提供其他答案)。

.split(".")

尝试使用问题中的6个例子:

public static boolean match(String s1, String s2) {
    String[] a1 = s1.split("\\.", 4);
    String[] a2 = s2.split("\\.", 4);
    if (a1.length != a2.length) {
        return false;
    }
    if (a1[0].equals("1") && a2[0].equals("2")) {
        if (a1.length == 2) {
            return a1[1].equals(a2[1]);
        } else if (a1.length == 3) {
            return (a1[1].equals(a2[1]) && a1[2].equals(a2[2]))
                    || (a1[1].equals(a2[2]) && a1[2].equals(a2[1]));
        }
    }
    return false;
}

打印:

    System.out.println("(1.111,2.111)      " + match("1.111", "2.111"));
    System.out.println("(1.121,2.111)      " + match("1.121", "2.111"));
    System.out.println("(1.11.22,2.11.22)  " + match("1.11.22", "2.11.22"));
    System.out.println("(1.11.22,2.111.22) " + match("1.11.22", "2.111.22"));
    System.out.println("(1.22.11,2.11.22)  " + match("1.22.11", "2.11.22"));
    System.out.println("(1.11.22,2.111.22) " + match("1.11.22", "2.111.22"));

答案 3 :(得分:0)

我想如下:

string[] arr1 = pattern1.split
string[] arr2 = pattern2.split
int hash1 = arr1[0].hashCode() + arr1[1].hashCode();
int hash2 = arr2[0].hashCode() + arr2[1].hashCode();
if(hash1 = hash2)=> pattern1 == pattern2

答案 4 :(得分:0)

从字符串中删除模式从字符串中提取字符,方法是在点周围拆分(假设你的vars里面没有点),放置它们在集合(集合不保留顺序,因此自动解决忽略位置的问题),检查集合的相等性

正在运行演示:https://ideone.com/5MwOHC

示例代码:

final static String pattern1head = "blablabla.";
final static String pattern2head = "yada yada.";

private static Set<String> extractVars(String v){
    if      (v.startsWith(pattern1head)) { v = v.replace(pattern1head,""); }
    else if (v.startsWith(pattern2head)) { v = v.replace(pattern2head,""); }
    else                                 { return null; }           

    return new HashSet<String>(Arrays.asList(v.split("\\.")));
}

private static void checkEquality(String v1, String v2) {
    System.out.println("\n"+v1+" == "+v2+" ? " + extractVars(v1).equals(extractVars(v2)));  
} 


public static void main (String[] args) throws java.lang.Exception {
    String v1 = "blablabla.123.456";
    String v2 = "yada yada.123.456";
    String v3 = "yada yada.456.123";
    String v4 = "yada yada.123.456789";

    checkEquality(v1,v2);
    checkEquality(v1,v3);
    checkEquality(v1,v4);
    checkEquality(v2,v3);
    checkEquality(v2,v4);
}

输出:

blablabla.123.456 == yada yada.123.456 ? true

blablabla.123.456 == yada yada.456.123 ? true

blablabla.123.456 == yada yada.123.456789 ? false

yada yada.123.456 == yada yada.456.123 ? true

yada yada.123.456 == yada yada.123.456789 ? false

答案 5 :(得分:0)

这可以按如下方式完成:

  • 当我们检查第一个字符串和第一个模式是否匹配时,我们在模式中提取与占位符(var1,var2,...)对应的字符串中的值的映射;
  • 当我们检查第二个字符串和第二个模式是否匹配时,我们还会根据占位符的值检查第二个字符串。

这很有趣,因为地图占位符 - &gt;为一对夫妇计算一次的值(第一个字符串,第一个模式), 并可用于检查每对(第二个字符串,第二个模式)。

代码中的翻译:从(第一个字符串,第一个模式)创建类型为PatternMatcher的对象。该对象将包含地图valueByPlaceHolder 用来检查其他夫妻。

以下是代码的相关部分。

检查字符串和模式是否匹配+创建地图:

private static Optional<Map<String, String>> extractValueByPlaceHolder(
        String[] sChunks, String[] patternChunks) {
    // string and pattern should have the same length
    if (sChunks.length != patternChunks.length)
        return Optional.empty();

    Map<String, String> valueByPlaceHolder = new HashMap<>(sChunks.length);
    for (int i = 0; i < patternChunks.length; i++) {
        String patternChunk = patternChunks[i];
        String sChunk = sChunks[i];
        if (isAPlaceHolder(patternChunk)) { // first char = {, last char = }
            valueByPlaceHolder.put(patternChunk, sChunk); // just get the value
        } else if (!patternChunk.equals(sChunk)) {
            // if it's not a placeholder, the chunks should be the same in the string
            // and the pattern
            return Optional.empty(); 
        }
    }
    return Optional.of(valueByPlaceHolder);
}

检查其他字符串和其他模式是否匹配+与第一个(字符串,模式)对的比较:

public boolean check(String[] otherChunks, String[] otherPatternChunks) {
    // other string and other pattern should have the same length, other string and string too
    if (otherChunks.length != this.chunks_length || otherChunks.length != otherPatternChunks.length)
        return false;

    for (int i = 0; i < otherChunks.length; i++) {
        String otherPatternChunk = otherPatternChunks[i];
        String otherChunk = otherChunks[i];
        // get the value from the first string if a it's placeholder, else keep the pattern chunk 
        String expectedChunk = this.valueByPlaceHolder
                .getOrDefault(otherPatternChunk, otherPatternChunk);

        // the chunk is neither equal to the value of the placeholder, nor to the chunk of the pattern 
        if (!expectedChunk.equals(otherChunk))
                return false;
    }
    return true;
}