Revision: 8743
http://languagetool.svn.sourceforge.net/languagetool/?rev=8743&view=rev
Author: dominikoeo
Date: 2012-12-31 11:56:45 +0000 (Mon, 31 Dec 2012)
Log Message:
-----------
- additional regexp checker which warns about minor issue
like [m|n] in regexp which should most certainly be [mn].
Modified Paths:
--------------
trunk/JLanguageTool/src/test/java/org/languagetool/rules/patterns/PatternRuleTest.java
Modified:
trunk/JLanguageTool/src/test/java/org/languagetool/rules/patterns/PatternRuleTest.java
===================================================================
---
trunk/JLanguageTool/src/test/java/org/languagetool/rules/patterns/PatternRuleTest.java
2012-12-31 11:28:58 UTC (rev 8742)
+++
trunk/JLanguageTool/src/test/java/org/languagetool/rules/patterns/PatternRuleTest.java
2012-12-31 11:56:45 UTC (rev 8743)
@@ -1,6 +1,6 @@
-/* LanguageTool, a natural language style checker
+/* LanguageTool, a natural language style checker
* Copyright (C) 2005 Daniel Naber (http://www.danielnaber.de)
- *
+ *
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
@@ -19,7 +19,9 @@
package org.languagetool.rules.patterns;
import java.io.IOException;
+import java.lang.String;
import java.util.*;
+import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
@@ -49,9 +51,9 @@
// regexp if and only if it is not enclosed on both sides by those
characters.
// This is to cope with Polish POS tags which contain dots without being
// a regexp.
- private static final Pattern PROBABLE_PATTERN =
Pattern.compile("(.+[+?^{}|\\[\\]].*)|(.*[+?^{}|\\[\\]].+)|(\\(.*\\))|(\\\\[^0-9].*)|[^cfmnt123]\\.|\\.[^ampvngl]|(.+\\.$)");
- private static final Pattern CASE_PATTERN = Pattern.compile("\\[(.)(.)\\]");
+ private static final Pattern PROBABLE_PATTERN =
Pattern.compile("(.+[+?^{}()|\\[\\]].*)|(.*[+?^{}()|\\[\\]].+)|(\\(.*\\))|(\\\\[^0-9].*)|[^cfmnt123]\\.|\\.[^ampvngl]|(.+\\.$)");
private static final Pattern EMPTY_DISJUNCTION =
Pattern.compile("^[|]|[|][|]|[|]$");
+ private static final Pattern CHAR_SET_PATTERN =
Pattern.compile("(\\(\\?-i\\))?.*(?<!\\\\)\\[^?([^\\]]+)\\]");
private static JLanguageTool langTool;
@@ -69,7 +71,7 @@
public void testGrammarRulesFromXML2() throws IOException {
new PatternRule("-1", Language.ENGLISH, Collections.<Element>emptyList(),
"", "", "");
}
-
+
public void testGrammarRulesFromXML(Set<Language> ignoredLanguages) throws
IOException {
for (final Language lang : Language.LANGUAGES) {
if (ignoredLanguages != null && ignoredLanguages.contains(lang)) {
@@ -102,7 +104,7 @@
}
private void testGrammarRulesFromXML(final List<PatternRule> rules,
- final JLanguageTool languageTool,
+ final JLanguageTool languageTool,
final JLanguageTool
allRulesLanguageTool, final Language lang) throws IOException {
final HashMap<String, PatternRule> complexRules = new HashMap<String,
PatternRule>();
for (final PatternRule rule : rules) {
@@ -139,7 +141,7 @@
if (element.isReferenceElement()) {
continue;
}
-
+
// Check whether token value is consistent with regexp="..."
warnIfElementNotKosher(
element.getString(),
@@ -147,7 +149,8 @@
element.getCaseSensitive(),
element.getNegation(),
element.isInflected(),
- lang, rule.getId() + ":" + rule.getSubId());
+ lang, rule.getId() + ":" + rule.getSubId(),
+ i);
// Check postag="..." is consistent with postag_regexp="..."
warnIfElementNotKosher(
@@ -156,7 +159,8 @@
element.getCaseSensitive(),
element.getPOSNegation(),
false,
- lang, rule.getId() + ":" + rule.getSubId() + " (POS tag)");
+ lang, rule.getId() + ":" + rule.getSubId() + " (POS tag)",
+ i);
List<Element> exceptionElements = new ArrayList<Element>();
if (element.getExceptionList() != null) {
@@ -182,7 +186,8 @@
exception.getNegation(),
exception.isInflected(),
lang,
- rule.getId() + ":" + rule.getSubId()+ " (exception in token ["
+ i + "])");
+ rule.getId() + ":" + rule.getSubId()+ " (exception in token ["
+ i + "])",
+ i);
}
// Check postag="..." of exception is consistent with
postag_regexp="..."
warnIfElementNotKosher(
@@ -192,7 +197,8 @@
exception.getPOSNegation(),
false,
lang,
- rule.getId() + ":" + rule.getSubId() + " (exception in POS tag
of token [" + i + "])");
+ rule.getId() + ":" + rule.getSubId() + " (exception in POS tag
of token [" + i + "])",
+ i);
// Search for duplicate exceptions (which are useless).
// Since there are 2 nested loops on the list of exceptions,
@@ -260,7 +266,7 @@
return false;
}
- // We should not need to check for:
+ // We should not need to check for:
// - isCaseSensitive() since an exception without isCaseSensitive
// imply the one with isCaseSensitive.
// - isInflected() since an exception with inflected="yes"
@@ -281,56 +287,83 @@
final boolean isCaseSensitive,
final boolean isNegated,
final boolean isInflected,
- final Language lang, final String ruleId) {
+ final Language lang,
+ final String ruleId,
+ final int tokenIndex) {
if (!isRegularExpression
&& PROBABLE_PATTERN.matcher(stringValue).find()) {
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " contains " + "\"" + stringValue
+ + ruleId + ", token [" + tokenIndex + "], contains " + "\"" +
stringValue
+ "\" that is not marked as regular expression but probably is
one.");
}
if (isRegularExpression && stringValue.isEmpty()) {
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " contains an empty string " + "\"" + stringValue
- + "\" that is marked as regular expression.");
+ + ruleId + ", token [" + tokenIndex + "], contains an empty string "
+ "\""
+ + stringValue + "\" that is marked as regular expression.");
} else if (isRegularExpression
&& !PROBABLE_PATTERN.matcher(stringValue)
.find()) {
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " contains " + "\"" + stringValue
+ + ruleId + ", token [" + tokenIndex + "], contains " + "\"" +
stringValue
+ "\" that is marked as regular expression but probably is not
one.");
}
if (isNegated && stringValue.isEmpty()) {
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " marked as negated but is empty so the negation is
useless. Did you mix up negate=\"yes\" and negate_pos=\"yes\"?");
+ + ruleId + ", token [" + tokenIndex + "], marked as negated but is "
+ + "empty so the negation is useless. Did you mix up "
+ + "negate=\"yes\" and negate_pos=\"yes\"?");
}
if (isInflected && stringValue.isEmpty()) {
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " contains " + "\"" + stringValue
+ + ruleId + ", token [" + tokenIndex + "], contains " + "\"" +
stringValue
+ "\" that is marked as inflected but is empty, so the attribute is
redundant.");
}
if (isRegularExpression && ".*".equals(stringValue)) {
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " marked as regular expression contains "
+ + ruleId + ", token [" + tokenIndex + "], marked as regular
expression contains "
+ "regular expression \".*\" which is useless: "
+ "(use an empty string without regexp=\"yes\" such as <token/>)");
}
+ if (isRegularExpression) {
+ final Matcher matcher = CHAR_SET_PATTERN.matcher(stringValue);
+ if (matcher.find()) {
+ // Remove things like \p{Punct} which are irrelevant here.
+ String s = matcher.group(2).replaceAll("\\\\p\\{[^}]*\\}", "");
+ // case sensitive if pattern contains (?-i).
+ if (s.indexOf('|') >= 0) {
+ System.err.println("The " + lang.toString() + " rule: "
+ + ruleId + ", token [" + tokenIndex + "], contains | (pipe) in "
+ + " regexp part [" + matcher.group(2)
+ + "] which is unlikely to be correct.");
+ }
- if (isRegularExpression && !isCaseSensitive) {
- final Matcher matcher = CASE_PATTERN.matcher(stringValue);
- if (matcher.find()) {
- final String letter1 = matcher.group(1);
- final String letter2 = matcher.group(2);
- final boolean lettersAreSameWithDifferentCase =
!letter1.equals(letter2)
- && letter1.toLowerCase().equals(letter2.toLowerCase());
- if (lettersAreSameWithDifferentCase) {
+ /* Disabled for now: it gives several errors in German
+ * which are minor and debatable whether it adds value.
+
+ final boolean caseSensitive = matcher.group(1) != null ||
isCaseSensitive;
+ if (!caseSensitive) {
+ s = s.toLowerCase();
+ }
+ char[] sorted = s.toCharArray();
+ // Sort characters in string, so finding duplicate characters can be
done by
+ // looking for identical adjacent characters.
+ java.util.Arrays.sort(sorted);
+ for (int i = 1; i < sorted.length; ++i) {
+ char c = sorted[i];
+ if ("&\\-|".indexOf(c) < 0 && sorted[i - 1] == c) {
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " contains regexp part [" + letter1 + letter2
- + "] which is useless without case_sensitive=\"yes\".");
+ + ruleId + ", token [" + tokenIndex + "], contains case "
+ + (caseSensitive ? "sensitive" : "insensitive")
+ + " regexp part [" + matcher.group(2)
+ + "] which contains duplicated char [" + c + "].");
+ break;
+ }
}
+ */
}
}
@@ -339,7 +372,8 @@
if (matcher.find()) {
// Empty disjunctions in regular expression are most likely not
intended.
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " contains empty disjunction | within " + "\"" +
stringValue + "\".");
+ + ruleId + ", token [" + tokenIndex + "], contains empty "
+ + "disjunction | within " + "\"" + stringValue + "\".");
}
final String[] groups = stringValue.split("\\)");
for (final String group : groups) {
@@ -352,12 +386,14 @@
if (partSet.contains(part)) {
// Duplicate disjunction parts "foo|foo".
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " contains duplicated disjunction part ("
+ + ruleId + ", token [" + tokenIndex + "], contains "
+ + "duplicated disjunction part ("
+ part + ") within " + "\"" + stringValue + "\".");
} else {
// Duplicate disjunction parts "Foo|foo" since element ignores
case.
System.err.println("The " + lang.toString() + " rule: "
- + ruleId + " contains duplicated non case sensitive
disjunction part ("
+ + ruleId + ", token [" + tokenIndex + "], contains
duplicated "
+ + "non case sensitive disjunction part ("
+ part + ") within " + "\"" + stringValue + "\". Did you "
+ "forget case_sensitive=\"yes\"?");
}
@@ -449,20 +485,20 @@
assertSuggestionsDoNotCreateErrors(languageTool, rule,
badSentence, matches);
}
}
-
+
// check for overlapping rules
/*matches = getMatches(rule, badSentence, languageTool);
final List<RuleMatch> matchesAllRules =
allRulesLanguageTool.check(badSentence);
for (RuleMatch match : matchesAllRules) {
if (!match.getRule().getId().equals(rule.getId()) && matches.length
!= 0
&& rangeIsOverlapping(matches[0].getFromPos(),
matches[0].getToPos(), match.getFromPos(), match.getToPos()))
- System.err.println("WARN: " + lang.getShortName() + ": '" +
badSentence + "' in "
+ System.err.println("WARN: " + lang.getShortName() + ": '" +
badSentence + "' in "
+ rule.getId() + " also matched " +
match.getRule().getId());
}*/
}
}
-
+
/**
* returns true if [a, b] has at least one number in common with [x, y]
*/
@@ -511,7 +547,7 @@
/*
final List<RuleMatch> matches =
allRulesLanguageTool.check(goodSentence);
for (RuleMatch match : matches) {
- System.err.println("WARN: " + lang.getShortName() + ": '" +
goodSentence + "' did not match "
+ System.err.println("WARN: " + lang.getShortName() + ": '" +
goodSentence + "' did not match "
+ rule.getId() + " but matched " + match.getRule().getId());
}
*/
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
------------------------------------------------------------------------------
Master Visual Studio, SharePoint, SQL, ASP.NET, C# 2012, HTML5, CSS,
MVC, Windows 8 Apps, JavaScript and much more. Keep your skills current
with LearnDevNow - 3,200 step-by-step video tutorials by Microsoft
MVPs and experts. SALE $99.99 this month only -- learn more at:
http://p.sf.net/sfu/learnmore_122412
_______________________________________________
Languagetool-commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/languagetool-commits