Skip to content

Commit

Permalink
Improved search query parser
Browse files Browse the repository at this point in the history
  • Loading branch information
libgenapps committed Jan 1, 2018
1 parent ee27a6b commit f8e6edc
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 23 deletions.
1 change: 1 addition & 0 deletions LibgenDesktop.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@
<Compile Include="Infrastructure\ViewModelEvent.cs" />
<Compile Include="Infrastructure\WindowContext.cs" />
<Compile Include="Infrastructure\WindowManager.cs" />
<Compile Include="Models\Database\SearchQueryParser.cs" />
<Compile Include="Models\Entities\DatabaseMetadata.cs" />
<Compile Include="Models\Entities\FictionBook.cs" />
<Compile Include="Models\Entities\SciMagArticle.cs" />
Expand Down
24 changes: 1 addition & 23 deletions Models/Database/LocalDatabase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -773,29 +773,7 @@ private SciMagArticle ReadSciMagArticle(SQLiteDataReader dataReader)

private string EscapeSearchQuery(string originalSearchQuery)
{
List<string> searchQueryBuilder = new List<string>();
foreach (string searchQueryPart in originalSearchQuery.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
switch (searchQueryPart)
{
case "AND":
case "OR":
case "NOT":
searchQueryBuilder.Add(searchQueryPart);
continue;
default:
if (searchQueryPart.Length > 1 && searchQueryPart.EndsWith("*"))
{
searchQueryBuilder.Add($"\"{searchQueryPart.Substring(0, searchQueryPart.Length - 1)}\"*");
}
else
{
searchQueryBuilder.Add($"\"{searchQueryPart}\"");
}
break;
}
}
return String.Join(" ", searchQueryBuilder);
return SearchQueryParser.GetEscapedQuery(originalSearchQuery);
}

private string GetSearchCommandWithLimit(string searchCommand, int? resultLimit)
Expand Down
123 changes: 123 additions & 0 deletions Models/Database/SearchQueryParser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LibgenDesktop.Models.Database
{
internal class SearchQueryParser
{
private readonly string originalSearchQuery;

private SearchQueryParser(string originalSearchQuery)
{
this.originalSearchQuery = originalSearchQuery;
}

public static string GetEscapedQuery(string originalSearchQuery)
{
return new SearchQueryParser(originalSearchQuery).GetEscapedQuery();
}

private string GetEscapedQuery()
{
List<string> searchQueryBuilder = new List<string>();
bool isInQuotes = false;
int currentIndex = 0;
string currentQueryPart = String.Empty;
while (currentIndex < originalSearchQuery.Length)
{
char currentChar = originalSearchQuery[currentIndex];
switch (currentChar)
{
case '"':
if (isInQuotes)
{
currentQueryPart += currentChar;
isInQuotes = false;
if ((currentIndex < originalSearchQuery.Length - 1) && (originalSearchQuery[currentIndex + 1] == '*'))
{
currentIndex++;
currentQueryPart += '*';
}
if (currentQueryPart.Length > 0)
{
AddSearchQueryPart(searchQueryBuilder, currentQueryPart);
currentQueryPart = String.Empty;
}
}
else
{
if (currentQueryPart.Length > 0)
{
AddSearchQueryPart(searchQueryBuilder, currentQueryPart);
}
currentQueryPart = currentChar.ToString();
isInQuotes = true;
}
break;
case ' ':
if (isInQuotes)
{
currentQueryPart += currentChar;
}
else
{
if (currentQueryPart.Length > 0)
{
AddSearchQueryPart(searchQueryBuilder, currentQueryPart);
currentQueryPart = String.Empty;
}
}
break;
default:
currentQueryPart += currentChar;
break;
}
currentIndex++;
}
if (currentQueryPart.Length > 0)
{
if (isInQuotes)
{
currentQueryPart = currentQueryPart.Substring(1);
}
foreach (string remainingQueryPart in currentQueryPart.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
{
AddSearchQueryPart(searchQueryBuilder, remainingQueryPart);
}
}
return String.Join(" ", searchQueryBuilder);
}

private void AddSearchQueryPart(List<string> searchQueryBuilder, string searchQueryPart)
{
if (searchQueryPart.StartsWith("\""))
{
searchQueryBuilder.Add(searchQueryPart);
}
else
{
switch (searchQueryPart)
{
case "AND":
case "OR":
case "NOT":
searchQueryBuilder.Add(searchQueryPart);
break;
default:
if (searchQueryPart.Length > 1 && searchQueryPart.EndsWith("*"))
{
searchQueryBuilder.Add($"\"{searchQueryPart.Substring(0, searchQueryPart.Length - 1)}\"*");
}
else
{
searchQueryBuilder.Add($"\"{searchQueryPart}\"");
}
break;
}
}
}
}
}

0 comments on commit f8e6edc

Please sign in to comment.