Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes exception in preview using regexp search and regexp search without specified field #7073

Merged
merged 12 commits into from
Nov 21, 2020
2 changes: 1 addition & 1 deletion src/main/java/org/jabref/gui/preview/PreviewViewer.java
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ private void highlightSearchPattern() {
"var markInstance = new Mark(document.getElementById(\"content\"));" +
"markInstance.unmark({" +
" done: function(){" +
" markInstance.markRegExp(/" + pattern + "/gmi);" +
" markInstance.markRegExp(/" + pattern.replaceAll("(?<!\\\\)/", "\\\\/") + "/gmi);" +
k3KAW8Pnf7mkmdSMPHz27 marked this conversation as resolved.
Show resolved Hide resolved
" }" +
" });"
);
Expand Down
65 changes: 36 additions & 29 deletions src/main/java/org/jabref/logic/search/SearchQuery.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.StringJoiner;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.jabref.logic.l10n.Localization;
import org.jabref.model.entry.BibEntry;
Expand All @@ -17,24 +18,41 @@
import org.jabref.model.search.rules.SentenceAnalyzer;

public class SearchQuery implements SearchMatcher {

/**
* Regex pattern for escaping special characters in javascript regular expressions
*/
public static final Pattern JAVASCRIPT_ESCAPED_CHARS_PATTERN = Pattern.compile("[\\.\\*\\+\\?\\^\\$\\{\\}\\(\\)\\|\\[\\]\\\\/]");

/**
* The mode of escaping special characters in regular expressions
*/
private enum EscapeMode {
/**
* using \Q and \E marks
*/
JAVA,
JAVA {
@Override
String format(String regex) {
return Pattern.quote(regex);
}
},
/**
* escaping all javascript regex special characters separately
*/
JAVASCRIPT
JAVASCRIPT {
@Override
String format(String regex) {
return JAVASCRIPT_ESCAPED_CHARS_PATTERN.matcher(regex).replaceAll("\\\\$0");
}
};

/**
* Regex pattern for escaping special characters in javascript regular expressions
*/
private static final Pattern JAVASCRIPT_ESCAPED_CHARS_PATTERN = Pattern.compile("[.*+?^${}()|\\[\\]\\\\/]");

/**
* Attempt to escape all regex special characters.
*
* @param regex a string containing a regex expression
* @return a regex with all special characters escaped
*/
abstract String format(String regex);
}

private final String query;
Expand Down Expand Up @@ -128,8 +146,7 @@ public boolean isRegularExpression() {
}

/**
* Returns a list of words this query searches for.
* The returned strings can be a regular expression.
* Returns a list of words this query searches for. The returned strings can be a regular expression.
*/
public List<String> getSearchWords() {
if (isRegularExpression()) {
Expand All @@ -151,7 +168,9 @@ public Optional<Pattern> getJavaScriptPatternForWords() {
return joinWordsToPattern(EscapeMode.JAVASCRIPT);
}

/** Returns a regular expression pattern in the form (w1)|(w2)| ... wi are escaped if no regular expression search is enabled
/**
* Returns a regular expression pattern in the form (w1)|(w2)| ... wi are escaped if no regular expression search is enabled
*
* @param escapeMode the mode of escaping special characters in wi
*/
private Optional<Pattern> joinWordsToPattern(EscapeMode escapeMode) {
Expand All @@ -162,24 +181,12 @@ private Optional<Pattern> joinWordsToPattern(EscapeMode escapeMode) {
}

// compile the words to a regular expression in the form (w1)|(w2)|(w3)
StringJoiner joiner = new StringJoiner(")|(", "(", ")");
for (String word : words) {
if (regularExpression) {
joiner.add(word);
} else {
switch (escapeMode) {
case JAVA:
joiner.add(Pattern.quote(word));
break;
case JAVASCRIPT:
joiner.add(JAVASCRIPT_ESCAPED_CHARS_PATTERN.matcher(word).replaceAll("\\\\$0"));
break;
default:
throw new IllegalArgumentException("Unknown special characters escape mode: " + escapeMode);
}
}
Stream<String> joiner = words.stream();
if (!regularExpression) {
// Reformat string when we are looking for a literal match
joiner = joiner.map(escapeMode::format);
}
String searchPattern = joiner.toString();
String searchPattern = joiner.collect(Collectors.joining(")|(", "(", ")"));

if (caseSensitive) {
return Optional.of(Pattern.compile(searchPattern));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,7 @@ public Boolean visitComparison(SearchParser.ComparisonContext context) {
if (fieldDescriptor.isPresent()) {
return comparison(fieldDescriptor.get().getText(), ComparisonOperator.build(context.operator.getText()), right);
} else {
return new ContainBasedSearchRule(caseSensitive).applyRule(right, entry);
return SearchRules.getSearchRule(caseSensitive, regex).applyRule(right, entry);
k3KAW8Pnf7mkmdSMPHz27 marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ private static boolean isSimpleQuery(String query) {
return SIMPLE_EXPRESSION.matcher(query).matches();
}

private static SearchRule getSearchRule(boolean caseSensitive, boolean regex) {
static SearchRule getSearchRule(boolean caseSensitive, boolean regex) {
if (regex) {
return new RegexBasedSearchRule(caseSensitive);
} else {
Expand Down