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);
}
}
}
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)我将演示为wordhelp
制作正则表达式所需的步骤,但要求不明确,规则不严格,因此通常存在一些缺点
\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