From: <kp...@us...> - 2011-02-24 11:07:03
|
Revision: 19386 http://jedit.svn.sourceforge.net/jedit/?rev=19386&view=rev Author: kpouer Date: 2011-02-24 11:06:57 +0000 (Thu, 24 Feb 2011) Log Message: ----------- Entire word search rewritten : now the search is done as usual, then before returning the result it is checked to be a whole word, if not, the next result is searched (and checked). A whole word has the following conditions : start of word : beginning of the line starts with a symbol or space char before the first char is a symbol or space end of word: end of line ends with a symbol or space char next to the last char is a symbol or space Modified Paths: -------------- jEdit/trunk/org/gjt/sp/jedit/search/BoyerMooreSearchMatcher.java jEdit/trunk/org/gjt/sp/jedit/search/HyperSearchOperationNode.java jEdit/trunk/org/gjt/sp/jedit/search/HyperSearchRequest.java jEdit/trunk/org/gjt/sp/jedit/search/PatternSearchMatcher.java jEdit/trunk/org/gjt/sp/jedit/search/SearchAndReplace.java jEdit/trunk/org/gjt/sp/jedit/search/SearchDialog.java jEdit/trunk/org/gjt/sp/jedit/search/SearchMatcher.java Modified: jEdit/trunk/org/gjt/sp/jedit/search/BoyerMooreSearchMatcher.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/search/BoyerMooreSearchMatcher.java 2011-02-23 21:35:35 UTC (rev 19385) +++ jEdit/trunk/org/gjt/sp/jedit/search/BoyerMooreSearchMatcher.java 2011-02-24 11:06:57 UTC (rev 19386) @@ -31,7 +31,7 @@ */ public class BoyerMooreSearchMatcher extends SearchMatcher { - //{{{ BoyerMooreSearchMatcher constructor + //{{{ BoyerMooreSearchMatcher constructors /** * Creates a new string literal matcher. * @param pattern the search pattern @@ -39,6 +39,18 @@ */ public BoyerMooreSearchMatcher(String pattern, boolean ignoreCase) { + this(pattern, ignoreCase, false); + } + + /** + * Creates a new string literal matcher. + * @param pattern the search pattern + * @param ignoreCase <code>true</code> if you want to ignore case + * @param wholeWord <code>true</code> to search for whole word only + * @since 4.5pre1 + */ + public BoyerMooreSearchMatcher(String pattern, boolean ignoreCase, boolean wholeWord) + { this.pattern = pattern.toCharArray(); if(ignoreCase) { @@ -52,7 +64,9 @@ this.ignoreCase = ignoreCase; pattern_end = this.pattern.length - 1; - } //}}} + this.wholeWord = wholeWord; + } + //}}} //{{{ nextMatch() method @Override @@ -70,6 +84,18 @@ { returnValue.start = pos; returnValue.end = pos + pattern.length; + int _end = returnValue.end; + if (wholeWord && !isWholeWord(text, returnValue.start, _end)) + { + CharSequence subText = text.subSequence(_end, text.length()); + Match match = nextMatch(subText, + start, end, firstTime, reverse); + if (match == null) + return null; + match.start = match.start + _end; + match.end = match.start + pattern.length; + return match; + } return returnValue; } } //}}} Modified: jEdit/trunk/org/gjt/sp/jedit/search/HyperSearchOperationNode.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/search/HyperSearchOperationNode.java 2011-02-23 21:35:35 UTC (rev 19385) +++ jEdit/trunk/org/gjt/sp/jedit/search/HyperSearchOperationNode.java 2011-02-24 11:06:57 UTC (rev 19386) @@ -47,12 +47,14 @@ private final String searchString; private List<DefaultMutableTreeNode> resultNodes; private SearchMatcher searchMatcher; + private String noWordSep; //{{{ HyperSearchOperationNode constructor public HyperSearchOperationNode(String searchString, SearchMatcher searchMatcher) { this.searchString = searchString; this.searchMatcher = searchMatcher; + noWordSep = searchMatcher.getNoWordSep(); }//}}} //{{{ toString() method @@ -224,6 +226,10 @@ //{{{ getSearchMatcher() method public SearchMatcher getSearchMatcher() { + // The searchMatcher has to remember the noWordSep property that was used + // because in case of HyperSearchOperationNode, the same SearchMatcher + // is used for several Buffers that can be of different edit modes. + searchMatcher.setNoWordSep(noWordSep); return searchMatcher; }//}}} Modified: jEdit/trunk/org/gjt/sp/jedit/search/HyperSearchRequest.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/search/HyperSearchRequest.java 2011-02-23 21:35:35 UTC (rev 19385) +++ jEdit/trunk/org/gjt/sp/jedit/search/HyperSearchRequest.java 2011-02-24 11:06:57 UTC (rev 19386) @@ -241,6 +241,8 @@ private int doHyperSearch(Buffer buffer, int start, int end, DefaultMutableTreeNode bufferNode) { + String noWordSep = (String) buffer.getMode().getProperty("noWordSep"); + matcher.setNoWordSep(noWordSep); int resultCount = 0; JEditTextArea textArea = jEdit.getActiveView().getTextArea(); int caretLine = textArea.getBuffer() == buffer ? textArea.getCaretLine() : -1; Modified: jEdit/trunk/org/gjt/sp/jedit/search/PatternSearchMatcher.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/search/PatternSearchMatcher.java 2011-02-23 21:35:35 UTC (rev 19385) +++ jEdit/trunk/org/gjt/sp/jedit/search/PatternSearchMatcher.java 2011-02-24 11:06:57 UTC (rev 19386) @@ -49,6 +49,21 @@ pattern = search; flags = getFlag(ignoreCase); } + + /** + * Creates a new regular expression string matcher. + * @see java.util.regex.Pattern + * @param re the compiled regex + * @param ignoreCase <code>true</code> if you want to ignore case + * @param wholeWord <code>true</code> to search for whole word only + * @since jEdit 4.5pre1 + */ + public PatternSearchMatcher(Pattern re, boolean ignoreCase, boolean wholeWord) + { + this(re.pattern(), ignoreCase); + this.re = re; + this.wholeWord = wholeWord; + } /** * Creates a new regular expression already compiled. @@ -59,8 +74,7 @@ */ public PatternSearchMatcher(Pattern re, boolean ignoreCase) { - this(re.pattern(), ignoreCase); - this.re = re; + this(re, ignoreCase, false); } //}}} //{{{ nextMatch() method @@ -157,7 +171,14 @@ returnValue.start = _start; returnValue.end = _end; - + + if (wholeWord && !isWholeWord(text, _start, _end)) + { + if (!match.find()) + return null; + continue; + } + // For non-reversed searches, we break immediately // to return the first match. For reversed searches, // we continue until no more matches are found Modified: jEdit/trunk/org/gjt/sp/jedit/search/SearchAndReplace.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/search/SearchAndReplace.java 2011-02-23 21:35:35 UTC (rev 19385) +++ jEdit/trunk/org/gjt/sp/jedit/search/SearchAndReplace.java 2011-02-24 11:06:57 UTC (rev 19386) @@ -324,35 +324,12 @@ if (regexp) { - Pattern re = Pattern.compile(search, + Pattern re = Pattern.compile(search, PatternSearchMatcher.getFlag(ignoreCase)); - matcher = new PatternSearchMatcher(re, ignoreCase); + matcher = new PatternSearchMatcher(re, ignoreCase, wholeWord); } - else if(wholeWord) - { - String s = Pattern.quote(search); - String begin; - if (Character.isLetter(search.charAt(0))) - { - begin = "(?:\\b|^)"; - } - else - { - begin = "(?:\\B|^)"; - } - String end; - if (Character.isLetter(search.charAt(search.length()-1))) - { - end = "(?:\\b|$)"; - } - else - { - end = "(?:\\B|$)"; - } - matcher = new PatternSearchMatcher(begin+s+end, ignoreCase); - } else - matcher = new BoyerMooreSearchMatcher(search, ignoreCase); + matcher = new BoyerMooreSearchMatcher(search, ignoreCase, wholeWord); return matcher; } //}}} @@ -675,6 +652,9 @@ buffer.getLineOfOffset(start)) == start); endOfLine = true; } + + String noWordSep = (String) buffer.getMode().getProperty("noWordSep"); + matcher.setNoWordSep(noWordSep); SearchMatcher.Match match = matcher.nextMatch(text, startOfLine,endOfLine,firstTime,reverse); if(match != null) @@ -1212,6 +1192,8 @@ boolean smartCaseReplace) throws Exception { + String wordBreakChars = (String) buffer.getMode().getProperty("wordBreakChars"); + matcher.setNoWordSep(wordBreakChars); int occurCount = 0; boolean endOfLine = (buffer.getLineEndOffset( Modified: jEdit/trunk/org/gjt/sp/jedit/search/SearchDialog.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/search/SearchDialog.java 2011-02-23 21:35:35 UTC (rev 19385) +++ jEdit/trunk/org/gjt/sp/jedit/search/SearchDialog.java 2011-02-24 11:06:57 UTC (rev 19386) @@ -707,8 +707,6 @@ if(!reverseEnabled) searchForward.setSelected(true); - wholeWord.setEnabled(!regexp.isSelected()); - filter.setEnabled(searchAllBuffers.isSelected() || searchDirectory.isSelected()); Modified: jEdit/trunk/org/gjt/sp/jedit/search/SearchMatcher.java =================================================================== --- jEdit/trunk/org/gjt/sp/jedit/search/SearchMatcher.java 2011-02-23 21:35:35 UTC (rev 19385) +++ jEdit/trunk/org/gjt/sp/jedit/search/SearchMatcher.java 2011-02-24 11:06:57 UTC (rev 19386) @@ -22,6 +22,8 @@ package org.gjt.sp.jedit.search; +import org.gjt.sp.jedit.TextUtilities; + /** * An abstract class for matching strings. * @author Slava Pestov @@ -50,7 +52,80 @@ public abstract Match nextMatch(CharSequence text, boolean start, boolean end, boolean firstTime, boolean reverse); + /** + * @param noWordSep the chars that are considered as word chars for this search + * @since jEdit 4.5pre1 + */ + public void setNoWordSep(String noWordSep) + { + if (noWordSep == null) + this.noWordSep = "_"; + else + this.noWordSep = noWordSep; + } + + /** + * Returns the noWordSep that should be used. + * This is used by the HyperSearchOperationNode that + * needs to remember this property since it can have + * to restore it. + * @return the noWordSep property + */ + String getNoWordSep() + { + return noWordSep; + } + + /** + * Check if the result is a whole word + * @param text the full text search + * @param start the start match + * @param end the end match + * @return true if the word is a whole word + */ + protected boolean isWholeWord(CharSequence text, int start, int end) + { + if (start != 0) + { + char firstChar = text.charAt(start); + char prevChar = text.charAt(start - 1); + if (!isEndWord(firstChar, prevChar)) + { + return false; + } + } + if (end < text.length()) + { + char lastChar = text.charAt(end - 1); + char nextChar = text.charAt(end); + if (!isEndWord(lastChar, nextChar)) + { + return false; + } + } + return true; + } + + private boolean isEndWord(char current, char next) + { + int currentCharType = TextUtilities.getCharType(current, noWordSep); + if (currentCharType != TextUtilities.WORD_CHAR) + return true; + + int nextCharType = TextUtilities.getCharType(next, noWordSep); + return nextCharType != TextUtilities.WORD_CHAR; + } + protected Match returnValue; + /** + * true if this SearchMatcher search for whole words only. + */ + protected boolean wholeWord; + /** + * This should contains the noWordSep property of the edit mode of your buffer. + * It contains a list of chars that should be considered as word chars + */ + protected String noWordSep; //{{{ Match class public static class Match @@ -58,5 +133,11 @@ public int start; public int end; public String[] substitutions; + + @Override + public String toString() + { + return "Match[" + start + ',' + end + ']'; + } } //}}} } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |