![](/img/trans.png)
[英]Regex to limit words with specific combination of letters (in any order)
[英]Regex for words that miss a letter and also two letters that are inverted in order
我想詳細說明一個涵蓋以下場景的正則表達式:
搜索到的單詞是“馬鈴薯”。
如果用戶搜索“potaot”(他快速鍵入並且“o”手指比“t”手指快,則匹配。(完成)
如果用戶搜索“ptato”(他忘了一個字母),它會匹配。 (完成)
憑借我對正則表達式的了解,我能夠進一步發展:
(?=[potato]{5,6})p?o?t?a?t?o?
這個問題是它匹配像“otatop”這樣的反向詞,這是一個有點聰明但有點bezarre,和“ooooo”,這是完全不受歡迎的。 所以我沒有描述我不想要的東西。
我不希望重復的字母與“ooooo”,“ooopp”等相匹配(無法)
順便說一句,我正在使用C#。
不要使用正則表達式。
最好的解決方案就是簡單。 只有十一種可能不精確的匹配,所以只需枚舉它們:
List<string> inexactMatches = new List<string> {
"otato", "ptato", "poato", "potto", "potao", "potat",
"optato", "ptoato", "poatto", "pottao", "potaot"};
...
bool hasInexactMatch = inexactMatches.Contains(whatever);
輸入它們需要不到一分鍾的時間; 使用簡單的特定解決方案,而不是嘗試做一些瘋狂的正則表達式,這將花費你幾個小時來查找和調試。
如果你要堅持使用正則表達式,這里有一個有用的:
otato|ptato|poato|potto|potao|potat|optato|ptoato|poatto|pottao|potaot
再說一次:更簡單更好。
現在,人們可能會認為你想要解決這個問題,而不是“馬鈴薯”。 在這種情況下,您可能已經這么說了 - 但無論如何,我們可以提出一些簡單的解決方案。
首先,讓我們枚舉從目標字符串中省略一個字母的所有字符串。 字符串是IEnumerable<char>
所以讓我們解決一般問題:
static IEnumerable<T> OmitAt<T>(this IEnumerable<T> items, int i) =>
items.Take(i).Concat(items.Skip(i + 1));
這有點粗略地列舉了兩次序列,但我不打算強調它。 現在讓我們為字符串制作一個特定的版本:
static IEnumerable<string> Omits(this string s) =>
Enumerable
.Range(0, s.Length)
.Select(i => new string(s.OmitAt(i).ToArray()));
大。 現在我們可以說"frob".Omits()
並回來rob, fob, frb, fro
。
現在讓我們進行交換。 再次,首先解決一般問題:
static void Swap<T>(ref T x, ref T y)
{
T t = x;
x = y;
y = t;
}
static T[] SwapAt<T>(this IEnumerable<T> items, int i)
{
T[] newItems = items.ToArray();
Swap(ref newItems[i], ref newItems[i + 1]);
return newItems;
}
現在我們可以解決它的字符串:
static IEnumerable<string> Swaps(this string s) =>
Enumerable
.Range(0, s.Length - 1)
.Select(i => new string(s.SwapAt(i)));
現在我們完成了:
string source = "potato";
string target = whatever;
bool match =
source.Swaps().Contains(target) ||
source.Omits().Contains(target);
十分簡單。 使用簡單,直接,正確的算法解決一般問題,這些算法可以組成更大的解決方案 。 我的算法都不超過三行,很容易看出它們是正確的。
這里選擇的武器是相似(或距離)匹配算法。 比較相似度算法可以很好地概述最常見的距離度量/算法。
問題是沒有單一的最佳指標。 選擇取決於例如輸入類型,精度要求,速度,資源可用性等。然而, 比較算法可能是混亂的 。
兩個最常建議的指標是Levenshtein距離和Jaro-Winkler:
Levenshtein距離提供了兩個字符串之間的相似性度量,可以說比其他一些指標更不寬容,更直觀。 (Levenshtein距離的修改版本就像Damerau-Levenshtein距離,其中包括換位,這可能更適合您的使用案例。)
一些人聲稱Jaro-Winkler,它提供兩個字符串之間的相似性度量,允許字符轉置到一定程度調整公共前綴的權重,距離是“目前可用的最高性能和准確的近似字符串匹配算法之一[Cohen,et al 。],[溫克勒]。“ 然而,選擇仍然在很大程度上取決於用例,並且無法從特定研究中得出一般性結論,例如名稱匹配Cohen等。 2003年 。
您可以在NuGet上找到大量的軟件包,它們為您提供各種相似度算法( a , b , c ), 模糊匹配 ,語音等,以便將此功能添加到您的站點或應用程序中。
模糊匹配也可以直接在數據庫層上使用。 對於大多數數據庫系統(例如MySQL , SQL Server )或者已經內置( Oracle , PostgreSQL ),可以找到Levenshtein距離的實現 。
根據您的具體用例,您還可以使用基於雲的解決方案(即使用基於AWS , Azure等的微服務或自行滾動 )來獲得類似於自動提取的模糊搜索/匹配。
這樣做最簡單:
static void Main(string[] args)
{
string correctWord = "Potato";
string incorrectSwappedWord = "potaot";
string incorrectOneLetter = "ptato";
// Returns true
bool swapped = SwappedLettersMatch(correctWord, incorrectSwappedWord);
// Returns true
bool oneLetter = OneLetterOffMatch(correctWord, incorrectOneLetter);
}
public static bool OneLetterOffMatch(string str, string input)
{
int ndx = 0;
str = str.ToLower();
input = input.ToLower();
if (string.IsNullOrWhiteSpace(str) || string.IsNullOrWhiteSpace(input))
{
return false;
}
while (ndx < str.Length)
{
string newStr = str.Remove(ndx, 1);
if (input == newStr)
{
return true;
}
ndx++;
}
return false;
}
public static bool SwappedLettersMatch(string str, string input)
{
if (string.IsNullOrWhiteSpace(str) || string.IsNullOrWhiteSpace(input))
{
return false;
}
if (str.Length != input.Length)
{
return false;
}
str = str.ToLower();
input = input.ToLower();
int ndx = 0;
while (ndx < str.Length)
{
if (ndx == str.Length - 1)
{
return false;
}
string newStr = str[ndx + 1].ToString() + str[ndx];
if (ndx > 0)
{
newStr = str.Substring(0, ndx) + newStr;
}
if (str.Length > ndx + 2)
{
newStr = newStr + str.Substring(ndx + 2);
}
if (newStr == input)
{
return true;
}
ndx++;
}
return false;
}
OneLetterOffMatch
將返回true,如果只有一個字符丟失,則匹配關閉。 當交換兩個字母時, SwappedLettersMatch
將返回true是否存在匹配。 這些函數不區分大小寫,但如果您需要區分大小寫的版本,只需刪除對.ToLower()
的調用。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.