Java tutorial
/* LanguageTool, a natural language style checker * Copyright (C) 2013 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 * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 * USA */ package org.languagetool.dev.wikipedia; import org.apache.commons.lang3.StringUtils; import org.languagetool.rules.RuleMatch; import xtc.tree.Location; import java.util.ArrayList; import java.util.List; /** * Applies the rule suggestions to a text, considering a mapping so the * suggestion can be applied to the original markup of a text. */ public class SuggestionReplacer { private final PlainTextMapping textMapping; private final String originalText; private final ErrorMarker errorMarker; /** * @param originalText the original text that includes markup */ public SuggestionReplacer(PlainTextMapping textMapping, String originalText) { // use <<span>> to avoid clashes with <span> in original markup: this(textMapping, originalText, new ErrorMarker("<<span class=\"error\">>", "<</span>>")); } /** * @since 2.6 */ public SuggestionReplacer(PlainTextMapping textMapping, String originalText, ErrorMarker errorMarker) { this.textMapping = textMapping; this.originalText = originalText; this.errorMarker = errorMarker; } /** * Applies the suggestions from the rule to the original text. For rules that * have no suggestion, a pseudo-correction is generated that contains the same * text as before. */ public List<RuleMatchApplication> applySuggestionsToOriginalText(RuleMatch match) { List<String> replacements = new ArrayList<>(match.getSuggestedReplacements()); boolean hasRealReplacements = replacements.size() > 0; if (!hasRealReplacements) { // create a pseudo replacement with the error text itself String plainText = textMapping.getPlainText(); replacements.add(plainText.substring(match.getFromPos(), match.getToPos())); } List<RuleMatchApplication> ruleMatchApplications = new ArrayList<>(); Location fromPosLocation = textMapping.getOriginalTextPositionFor(match.getFromPos() + 1); // not zero-based! Location toPosLocation = textMapping.getOriginalTextPositionFor(match.getToPos() + 1); /*System.out.println("========="); System.out.println(textMapping.getMapping()); System.out.println("========="); System.out.println(textMapping.getPlainText()); System.out.println("========="); System.out.println(originalText); System.out.println("=========");*/ int fromPos = LocationHelper.absolutePositionFor(fromPosLocation, originalText); int toPos = LocationHelper.absolutePositionFor(toPosLocation, originalText); for (String replacement : replacements) { String errorText = textMapping.getPlainText().substring(match.getFromPos(), match.getToPos()); // the algorithm is off a bit sometimes due to the complex syntax, so consider the next whitespace: int contextFrom = findNextWhitespaceToTheLeft(originalText, fromPos); int contextTo = findNextWhitespaceToTheRight(originalText, toPos); /*System.out.println(match + ":"); System.out.println("match.getFrom/ToPos(): " + match.getFromPos() + "/" + match.getToPos()); System.out.println("from/toPosLocation: " + fromPosLocation + "/" + toPosLocation); System.out.println("from/toPos: " + fromPos + "/" + toPos); System.out.println("contextFrom/To: " + contextFrom + "/" + contextTo);*/ String context = originalText.substring(contextFrom, contextTo); String text = originalText.substring(0, contextFrom) + errorMarker.getStartMarker() + context + errorMarker.getEndMarker() + originalText.substring(contextTo); String newContext; if (StringUtils.countMatches(context, errorText) == 1) { newContext = context.replace(errorText, replacement); } else { // This may happen especially for very short strings. As this is an // error, we don't claim to have real replacements: newContext = context; hasRealReplacements = false; } String newText = originalText.substring(0, contextFrom) // we do a simple string replacement as that works even if our mapping is off a bit: + errorMarker.getStartMarker() + newContext + errorMarker.getEndMarker() + originalText.substring(contextTo); RuleMatchApplication application; if (hasRealReplacements) { application = RuleMatchApplication.forMatchWithReplacement(match, text, newText, errorMarker); } else { application = RuleMatchApplication.forMatchWithoutReplacement(match, text, newText, errorMarker); } ruleMatchApplications.add(application); } return ruleMatchApplications; } int findNextWhitespaceToTheRight(String text, int position) { for (int i = position; i < text.length(); i++) { if (Character.isWhitespace(text.charAt(i))) { return i; } } return text.length(); } int findNextWhitespaceToTheLeft(String text, int position) { for (int i = position; i >= 0; i--) { if (Character.isWhitespace(text.charAt(i))) { return i + 1; } } return 0; } }