Java 正则表达式:查找具有额外字符的单词

Java 正则表达式:查找具有额外字符的单词,java,regex,Java,Regex,我想在句子中找到“帮助”这个词。这本身就是一项容易的任务。然而,在某些情况下,这个词可能被写成heelp或hhelp,基本上包含比通常更多的字符。当然,有些例子比其他例子更现实 查找“帮助”的基本正则表达式(撇开大小写差异-(?i)可以涵盖这一点)是: 但是,这个正则表达式只检测直接的单词,不考虑可以添加的额外字符 替换双字符不是一个选项,因为有些单词通常存在(这不是一项容易的任务,您需要一个好的NLP(自然语言处理)库) 对于Java,这可能是一个项目 对于Perl,有一些模块,如(如果你在词

我想在句子中找到“帮助”这个词。这本身就是一项容易的任务。然而,在某些情况下,这个词可能被写成
heelp
hhelp
,基本上包含比通常更多的字符。当然,有些例子比其他例子更现实

查找“帮助”的基本正则表达式(撇开大小写差异-
(?i)
可以涵盖这一点)是:

但是,这个正则表达式只检测直接的单词,不考虑可以添加的额外字符


替换双字符不是一个选项,因为有些单词通常存在(这不是一项容易的任务,您需要一个好的NLP(自然语言处理)库)

对于Java,这可能是一个项目


对于Perl,有一些模块,如(如果你在词干分析之后)或PHP(如果你在使用类似的拼音词)。

这很有效。请在任何在线regex测试仪上试用,以确保它正是你想要的: 备注:这适用于任何数量的不需要的字母,如果您需要1个字母-“\w*”模式应替换为“\w?”(并相应地在java代码中)

\bh+\w*e+\w*l+\w*p+\b

更新*

下面是java代码,可以在任何单词上获得这样的正则表达式

public static String getRegExForWord(String word){
        char[] chars =  word.toCharArray();
        StringBuilder pattern = new StringBuilder("\\b");
        for (int i = 0; i < chars.length-1; i++) {
            pattern.append(chars[i]).append("+\\w*");
        }
        return pattern.append(chars[chars.length - 1]).append("+\\b").toString();
    }
公共静态字符串getRegExForWord(字符串字){
char[]chars=word.toCharArray();
StringBuilder模式=新StringBuilder(“\\b”);
for(int i=0;i
更新版本

h = h.trim();
h = h.replaceAll("\\s+", "\n");

Pattern p = Pattern.compile("(h+.*?e+.*?l+.*?p+)", Pattern.MULTILINE);
Matcher m = p.matcher(h);
while(m.find())
{
    System.out.println(m.group(1));
}

我向您提出以下(一般)解决方案:

import java.util.*;

public class LevenshteinDistance {                                               
    private static int minimum(int a, int b, int c) {                            
        return Math.min(Math.min(a, b), c);                                      
    }                                                                            

    public static int computeLevenshteinDistance(CharSequence lhs, CharSequence rhs) {      
        int[][] distance = new int[lhs.length() + 1][rhs.length() + 1];        

        for (int i = 0; i <= lhs.length(); i++)                                 
            distance[i][0] = i;                                                  
        for (int j = 1; j <= rhs.length(); j++)                                 
            distance[0][j] = j;                                                  

        for (int i = 1; i <= lhs.length(); i++)                                 
            for (int j = 1; j <= rhs.length(); j++)                             
                distance[i][j] = minimum(                                        
                        distance[i - 1][j] + 1,                                  
                        distance[i][j - 1] + 1,                                  
                        distance[i - 1][j - 1] + ((lhs.charAt(i - 1) == rhs.charAt(j - 1)) ? 0 : 1));

        return distance[lhs.length()][rhs.length()];                           
    }

  public static String compress(String s) {
    char[] chars = s.toCharArray();
    Character last_char = null;

    StringBuilder sb = new StringBuilder();
    for (Character c:chars) {
      if(c != last_char) {
        sb.append(c);
        last_char = c;
      }
    }
    return sb.toString();
  }

    public static void main(String[] argv) {
      String[] strings = {"heelp", "help", "heeeelp", "hhhheeeelllllpppp", "heeeklp", "hlep", "helper"};
      String[] dict = {"help", "helper"};

      String match = "", c;
      int min_distance, distance;
      for(String s : strings) {
        c = compress(s);
        min_distance = computeLevenshteinDistance(c, "");

        for(String d : dict) {
          distance = computeLevenshteinDistance(c, d);
          System.out.println("compressed: "+c+ " dict: "+d+" distance: "+Integer.toString(distance));
          if(distance < min_distance) {
            match = d;
            min_distance = distance;
          }
        }

        System.out.println(s + " matches " + match);
      }
    }                                                                            
}
  • 压缩每个单词,这样就不会有任何重复的字母
  • 找到要匹配的单词词典
  • 匹配字典中具有最小Levenshtein距离的单词
  • 压缩应产生以下结果:

    heelp -> help
    help -> help
    heeeelp -> help
    hhhheeeelllllpppp -> help
    heeeklp -> heklp
    hlep -> hlep
    helper -> helper
    
    两个单词之间的Levenshtein距离(
    LD(word1,word2)
    )是要更改以使其相等的字符数。例如:

    hhhheeeelllllpppp -> help -> LD(help, help) = 0, LD(help, helper) = 2 <- help match
    heeeklp -> heklp -> LD(heklp, help) = 1, LD(heklp, helper) = 3 <- help match
    hlep -> hlep -> LD(hlep, help) = 2, LD(hlep, helper) = 3 <- help match
    helper -> helper -> LD(helper, help) = 2, LD(helper, helper) = 0 <- helper match
    

    \bh+\w{0,1}e+\w{0,1}l+\w{0,1}p+\b

    在regex101.com上对javascript进行了测试,以获得示例输入所需的结果。它比使用“*”更“紧凑”,只允许零个或一个零散字母。这与我的印象相符,即您允许任何数字中的正确字母,但错误字母只允许在两个正确字母之间出现一个

    将“帮助”与每个正确字母的任意数量(>0)按正确顺序匹配。 在每两(组)个正确的字母之间,允许有一个或零个其他“单词”字母(数字、字母、“?”)。单词必须以第一个正确的字母开头,以最后一个正确的字母结尾

    为了更精确地在正确的字母之间选择允许的字母,如果您不喜欢
    \w
    集,可以使用
    [所有允许的字母]


    我用
    {0,1}
    替换了
    ,以演示该语法的灵活性。

    使用普通正则表达式查找
    帮助后,需要使用“编辑距离”查找相似模式。这是用于拼写检查和单词推荐的度量。例如,如果您从“帮助”返回所有编辑距离为1的单词,您将获得:

    helpp
    heelp
    hellp
    hel
    belp
    ...
    
    帮助中编辑2的距离:

    heeelp
    helppp
    hhellp
    
    使用NLTK(Python NLP包),可以通过以下方式实现:

    my_word = 'help'
    corpus = {'w1', 'w2'} # Set of all words in your corpus
    
    word_distance = {}
    
    for word in corpus:
        if nltk.edit_distance(my_word, word) <= 2:
            word_distance[word] = nltk.edit_distance(my_word, word)
    
    # Sort dict by value if you choose to return greater edit distances
    results = sorted(word_distance, key=word_distance.get, reverse=True)
    print(results[:10])
    
    my_word='help'
    语料库={'w1','w2'}#语料库中所有单词的集合
    单词_距离={}
    对于语料库中的单词:
    
    如果nltk.edit_distance(my_word,word)我将演示为word
    help
    制作正则表达式所需的步骤,但要求不明确,规则不严格,因此通常存在一些缺点

    \bh+[a-z&&[^e]]*e+[a-z&&[^le]]*l+[a-z&&[^ p  l  e ]]*p+\b
               ^             ^^              ^  ^  ^
               |             ||              |  |--|-> [#2]
               |             ||              |-> [#1]
               |             ||-> Previous char(s) [#2]
               |             |-> [#1]
               |-> Next immediate character [#1]
    
    • [a-z&&[^lep]
      指除
      l
      e
      p
    要复制/粘贴的正则表达式:

    \bh+[a-z&&[^e]]*e+[a-z&&[^le]]*l+[a-z&&[^lep]]*p+\b
    

    看一看regexp特殊字符
    *
    +
    。你可以使用我假设你的意思是“heeeklp”是“(未找到)”,因为它里面有一个“k”
    ^(h+e+l+p+)$
    假设单词
    heeeklp
    你不想被匹配。如果你的目标真的是一个智能聊天系统,就像你之前在评论中所说的那样,那么这样的正则表达式将是无用的。首先,许多人错误地排列字母。因此
    hlep
    可能是一个寻求
    帮助的实际尝试。其次,有很多人包含其他非本意词语的词语。例如“助手”或“直升机”。也许关于NLP的答案对你的情况来说是正确的。为什么?用一个简短的正则表达式来解决这个问题似乎很简单,至少在我看来是这样的!?正如xander所说,它可以在不必拖动NLP的情况下解决。而且还有一个正则表达式也可以工作,所以NLP没有必要打开一个带有示例文本的regex101.com选项卡(
    heelp-help-heeelp-hhheeelllpppp-hlep-heeklp
    )中。此正则表达式(当前状态)作为一个组对
    hlep-help
    作出反应,即两个错误。(它不应对hlep作出反应,也不应将这两个视为一个组)哦,现在我明白了。我想你应该一次只接收一个单词。更新为只用空格分隔单词的字符串:)有点晚了,我知道,但在我的代码中,所有空格都被替换为“\n”,将它们放在新行上。问题中使用的换行格式是为了让我能够概述示例输入。现在我想(无法完全确定)您的答案有一个单词多行检查。是的,有。明白了。感谢您的澄清。这只适用于
    帮助
    !您的意思是为每个需要捕获的单词定义一个正则表达式吗?!@LunarWatcher我希望heeeklp匹配,因为它仍然包含单词“help”根据这句话,即使它有一个不相关的字符,像
    hheeeekklllllpppp这样的单词也应该
    
    heeelp
    helppp
    hhellp
    
    my_word = 'help'
    corpus = {'w1', 'w2'} # Set of all words in your corpus
    
    word_distance = {}
    
    for word in corpus:
        if nltk.edit_distance(my_word, word) <= 2:
            word_distance[word] = nltk.edit_distance(my_word, word)
    
    # Sort dict by value if you choose to return greater edit distances
    results = sorted(word_distance, key=word_distance.get, reverse=True)
    print(results[:10])
    
    \bh+[a-z&&[^e]]*e+[a-z&&[^le]]*l+[a-z&&[^ p  l  e ]]*p+\b
               ^             ^^              ^  ^  ^
               |             ||              |  |--|-> [#2]
               |             ||              |-> [#1]
               |             ||-> Previous char(s) [#2]
               |             |-> [#1]
               |-> Next immediate character [#1]
    
    \bh+[a-z&&[^e]]*e+[a-z&&[^le]]*l+[a-z&&[^lep]]*p+\b