1 19 20 package org.netbeans.modules.editor.lib2.search; 21 22 import java.util.Map ; 23 import java.util.regex.Matcher ; 24 import java.util.regex.Pattern ; 25 import java.util.regex.PatternSyntaxException ; 26 import javax.swing.text.BadLocationException ; 27 import javax.swing.text.Document ; 28 import org.netbeans.lib.editor.util.swing.DocumentUtilities; 29 import org.netbeans.modules.editor.lib2.DocUtils; 30 import org.openide.DialogDisplayer; 31 import org.openide.NotifyDescriptor; 32 import org.openide.util.NbBundle; 33 34 38 public class DocumentFinder 39 { 40 41 private static FalseBlocksFinder falseBlocksFinder; 42 private static FalseFinder falseFinder; 43 private static WholeWordsBlocksFinder wholeWordsBlocksFinder; 44 private static RegExpBlocksFinder regExpBlocksFinder; 45 private static StringBlocksFinder stringBlocksFinder; 46 private static WholeWordsBwdFinder wholeWordsBwdFinder; 47 private static WholeWordsFwdFinder wholeWordsFwdFinder; 48 private static RegExpBwdFinder regExpBwdFinder; 49 private static RegExpFwdFinder regExpFwdFinder; 50 private static StringBwdFinder stringBwdFinder; 51 private static StringFwdFinder stringFwdFinder; 52 53 54 private DocumentFinder() 55 { 56 } 57 58 59 private static DocFinder getFinder(Document doc, Map searchProps, boolean oppositeDir, boolean blocksFinder){ 60 String text = (String )searchProps.get(EditorFindSupport.FIND_WHAT); 61 if (text == null || text.length() == 0) { 62 if (blocksFinder) { 63 if (falseBlocksFinder == null){ 64 falseBlocksFinder = new FalseBlocksFinder(); 65 } 66 return falseBlocksFinder; 67 } else { 68 if (falseFinder == null){ 69 falseFinder = new FalseFinder(); 70 } 71 return falseFinder; 72 } 73 } 74 75 Boolean b = (Boolean )searchProps.get(EditorFindSupport.FIND_BACKWARD_SEARCH); 76 boolean bwdSearch = (b != null && b.booleanValue()); 77 if (oppositeDir) { bwdSearch = !bwdSearch; 79 } 80 81 b = (Boolean )searchProps.get(EditorFindSupport.FIND_MATCH_CASE); 82 boolean matchCase = (b != null && b.booleanValue()); 83 b = (Boolean )searchProps.get(EditorFindSupport.FIND_SMART_CASE); 84 boolean smartCase = (b != null && b.booleanValue()); 85 b = (Boolean )searchProps.get(EditorFindSupport.FIND_WHOLE_WORDS); 86 boolean wholeWords = (b != null && b.booleanValue()); 87 88 if (smartCase && !matchCase) { 89 int cnt = text.length(); 90 for (int i = 0; i < cnt; i++) { 91 if (Character.isUpperCase(text.charAt(i))) { 92 matchCase = true; 93 } 94 } 95 } 96 97 b = (Boolean ) searchProps.get(EditorFindSupport.FIND_REG_EXP); 98 boolean regExpSearch = (b!=null && b.booleanValue()); 99 100 Pattern pattern = null; 101 if (regExpSearch){ 102 try{ 103 pattern = PatternCache.getPattern(text, matchCase); 104 if (pattern == null){ 105 pattern = (matchCase) ? Pattern.compile(text, Pattern.MULTILINE) : Pattern.compile(text, Pattern.MULTILINE | Pattern.CASE_INSENSITIVE); PatternCache.putPattern(text, matchCase, pattern); 107 } 108 }catch(PatternSyntaxException pse){ 109 if (!blocksFinder){ 110 NotifyDescriptor msg = new NotifyDescriptor.Message( 111 pse.getDescription(), NotifyDescriptor.ERROR_MESSAGE); 112 msg.setTitle(NbBundle.getBundle(DocumentFinder.class).getString("pattern-error-dialog-title")); DialogDisplayer.getDefault().notify(msg); 114 } 115 PatternCache.putPattern(text, matchCase, null); 116 return null; 117 } 118 }else{ 119 PatternCache.clear(); 120 } 121 122 if (blocksFinder) { 123 if (wholeWords && !regExpSearch) { 124 if (wholeWordsBlocksFinder == null){ 125 wholeWordsBlocksFinder = new WholeWordsBlocksFinder(); 126 } 127 wholeWordsBlocksFinder.setParams(doc, text, matchCase); 128 return wholeWordsBlocksFinder; 129 } else { 130 if (regExpSearch){ 131 if (regExpBlocksFinder == null){ 132 regExpBlocksFinder = new RegExpBlocksFinder(); 133 } 134 regExpBlocksFinder.setParams(pattern, matchCase); 135 return regExpBlocksFinder; 136 }else{ 137 if (stringBlocksFinder == null){ 138 stringBlocksFinder = new StringBlocksFinder(); 139 } 140 stringBlocksFinder.setParams(text, matchCase); 141 return stringBlocksFinder; 142 } 143 } 144 } else { 145 if (wholeWords && !regExpSearch) { 146 if (bwdSearch) { 147 if (wholeWordsBwdFinder == null){ 148 wholeWordsBwdFinder = new WholeWordsBwdFinder(); 149 } 150 wholeWordsBwdFinder.setParams(doc, text, matchCase); 151 return wholeWordsBwdFinder; 152 } else { 153 if (wholeWordsFwdFinder == null){ 154 wholeWordsFwdFinder = new WholeWordsFwdFinder(); 155 } 156 wholeWordsFwdFinder.setParams(doc, text, matchCase); 157 return wholeWordsFwdFinder; 158 } 159 } else { 160 if (regExpSearch){ 161 if (bwdSearch) { 162 if (regExpBwdFinder == null){ 163 regExpBwdFinder = new RegExpBwdFinder(); 164 } 165 regExpBwdFinder.setParams(pattern, matchCase); 166 return regExpBwdFinder; 167 } else { 168 if (regExpFwdFinder == null){ 169 regExpFwdFinder = new RegExpFwdFinder(); 170 } 171 regExpFwdFinder.setParams(pattern, matchCase); 172 return regExpFwdFinder; 173 } 174 }else{ 175 if (bwdSearch) { 176 if (stringBwdFinder == null){ 177 stringBwdFinder = new StringBwdFinder(); 178 } 179 stringBwdFinder.setParams(text, matchCase); 180 return stringBwdFinder; 181 } else { 182 if (stringFwdFinder == null){ 183 stringFwdFinder = new StringFwdFinder(); 184 } 185 stringFwdFinder.setParams(text, matchCase); 186 return stringFwdFinder; 187 } 188 } 189 } 190 } 191 } 192 193 194 private static FindReplaceResult findReplaceImpl(String replaceText, Document doc, int startOffset, int endOffset, Map props, 195 boolean oppositeDir) throws BadLocationException { 196 int ret[] = new int[2]; 197 if (endOffset == -1){ 198 endOffset = doc.getLength(); 199 } 200 if (startOffset>endOffset){ 201 int temp = startOffset; 202 startOffset = endOffset; 203 endOffset = temp; 204 } 205 DocFinder finder = getFinder(doc, props, oppositeDir, false); 206 if (finder == null){ 207 return null; 208 } 209 finder.reset(); 210 CharSequence cs = DocumentUtilities.getText(doc, startOffset, endOffset - startOffset); 211 if (cs==null) return null; 212 int findRet = finder.find(startOffset, cs); 213 if (!finder.isFound()){ 214 ret[0] = -1; 215 return new FindReplaceResult(ret, replaceText); 216 } 217 ret[0] = startOffset + findRet; 218 219 if (finder instanceof StringFinder){ 220 int length = ((StringFinder)finder).getFoundLength(); 221 ret[1] = ret [0] + length; 222 } 223 224 if (finder instanceof RegExpFinder){ 225 Matcher matcher = ((RegExpFinder)finder).getMatcher(); 226 if (matcher != null && replaceText != null){ 227 CharSequence foundString = cs.subSequence(ret[0]-startOffset, ret[1]-startOffset); 228 matcher.reset(foundString); 229 if (matcher.find()){ 230 try{ 231 replaceText = matcher.replaceFirst(replaceText); 232 }catch(IndexOutOfBoundsException ioobe){ 233 NotifyDescriptor msg = new NotifyDescriptor.Message( 234 ioobe.getLocalizedMessage(), NotifyDescriptor.ERROR_MESSAGE); 235 msg.setTitle(NbBundle.getBundle(DocumentFinder.class).getString("pattern-error-dialog-title")); DialogDisplayer.getDefault().notify(msg); 237 return null; 238 } 239 } 240 } 241 } 242 return new FindReplaceResult(ret, replaceText); 243 } 244 245 254 public static int[] find(Document doc, int startOffset, int endOffset, Map props, 255 boolean oppositeDir) throws BadLocationException { 256 FindReplaceResult result = findReplaceImpl(null, doc, startOffset, endOffset, props, oppositeDir); 257 if (result == null){ 258 return null; 259 } 260 261 return result.getFoundPositions(); 262 } 263 264 public static int[] findBlocks(Document doc, int startOffset, int endOffset, 265 Map props, int blocks[]) throws BadLocationException { 266 BlocksFinder finder =(BlocksFinder) getFinder(doc, props, false, true); 267 if (finder == null){ 268 return blocks; 269 } 270 finder.reset(); 271 finder.setBlocks(blocks); 272 CharSequence cs = DocumentUtilities.getText(doc, startOffset, endOffset - startOffset); 273 if (cs==null){ 274 return null; 275 } 276 finder.find(startOffset, cs); 277 int ret [] = finder.getBlocks(); 278 return ret; 279 } 280 281 286 public static FindReplaceResult findReplaceResult(String replaceString, Document doc, int startOffset, int endOffset, Map props, 287 boolean oppositeDir) throws BadLocationException { 288 return findReplaceImpl(replaceString, doc, startOffset, endOffset, props, oppositeDir); 289 } 290 291 private interface DocFinder{ 292 293 public int find(int initOffset, CharSequence data); 294 295 public boolean isFound(); 296 297 public void reset(); 298 } 299 300 301 private static final class FalseBlocksFinder extends AbstractBlocksFinder { 302 303 public int find(int initOffset, CharSequence data) { 304 return -1; 305 } 306 307 } 308 309 310 private static class FalseFinder extends AbstractFinder 311 implements StringFinder { 312 313 public int find(int initOffset, CharSequence data) { 314 return -1; 315 } 316 317 public int getFoundLength() { 318 return 0; 319 } 320 321 } 322 323 324 325 private static abstract class AbstractBlocksFinder extends AbstractFinder 326 implements BlocksFinder { 327 328 private static int[] EMPTY_INT_ARRAY = new int[0]; 329 330 private int[] blocks = EMPTY_INT_ARRAY; 331 332 private int blocksInd; 333 334 private boolean closed; 335 336 public void reset() { 337 blocksInd = 0; 338 closed = false; 339 } 340 341 public int[] getBlocks() { 342 if (!closed) { closeBlocks(); 344 closed = true; 345 } 346 return blocks; 347 } 348 349 public void setBlocks(int[] blocks) { 350 this.blocks = blocks; 351 closed = false; 352 } 353 354 protected void addBlock(int blkStartPos, int blkEndPos) { 355 if (blocksInd == blocks.length) { 356 int[] dbl = new int[blocks.length * 2]; 357 System.arraycopy(blocks, 0, dbl, 0, blocks.length); 358 blocks = dbl; 359 } 360 blocks[blocksInd++] = blkStartPos; 361 blocks[blocksInd++] = blkEndPos; 362 } 363 364 365 protected void closeBlocks() { 366 addBlock(-1, -1); 367 } 368 369 public String debugBlocks() { 370 StringBuffer buf = new StringBuffer (); 371 int ind = 0; 372 while (blocks[ind] != -1) { 373 buf.append((ind/2 + 1) + ": [" + blocks[ind] + ", " + blocks[ind + 1] + "]\n"); ind+= 2; 375 } 376 return buf.toString(); 377 } 378 379 } 380 381 385 private interface BlocksFinder extends DocFinder { 386 387 391 public void setBlocks(int[] blocks); 392 393 397 public int[] getBlocks(); 398 399 } 400 401 402 405 private static abstract class AbstractFinder implements DocFinder { 406 407 408 protected boolean found; 409 410 411 public final boolean isFound() { 412 return found; 413 } 414 415 416 public void reset() { 417 found = false; 418 } 419 420 } 421 422 423 427 private interface StringFinder extends DocFinder { 428 429 434 public int getFoundLength(); 435 436 } 437 438 439 443 private static final class WholeWordsBlocksFinder extends AbstractBlocksFinder { 444 445 char chars[]; 446 447 int stringInd; 448 449 boolean matchCase; 450 451 boolean insideWord; 452 453 boolean firstCharWordPart; 454 455 boolean wordFound; 456 457 Document doc; 458 459 public WholeWordsBlocksFinder() { 460 } 461 462 public void setParams(Document doc, String s, boolean matchCase){ 463 this.matchCase = matchCase; 464 this.doc = doc; 465 chars = (matchCase ? s : s.toLowerCase()).toCharArray(); 466 firstCharWordPart = DocUtils.isIdentifierPart(doc, chars[0]); 467 } 468 469 public void reset() { 470 super.reset(); 471 insideWord = false; 472 wordFound = false; 473 stringInd = 0; 474 } 475 476 public int find(int initOffset, CharSequence data) { 477 int offset = 0; 478 int limitPos = data.length(); 479 int limitOffset = limitPos - 1; 480 while (offset >= 0 && offset < limitPos) { 481 char ch = data.charAt(offset); 482 483 if (!matchCase) { 484 ch = Character.toLowerCase(ch); 485 } 486 487 if (wordFound) { 489 if (DocUtils.isIdentifierPart(doc, ch)) { insideWord = firstCharWordPart; 491 offset -= chars.length - 1; 492 } else { 493 int blkEnd = initOffset + offset; 494 addBlock(blkEnd - chars.length, blkEnd); 495 insideWord = false; 496 offset++; 497 } 498 wordFound = false; 499 stringInd = 0; 500 continue; 501 } 502 503 if (stringInd == 0) { if (ch != chars[0] || insideWord) { insideWord = DocUtils.isIdentifierPart(doc, ch); 506 offset++; 507 } else { stringInd = 1; if (chars.length == 1) { 510 if (offset == limitOffset) { 511 int blkStart = initOffset + offset; 512 addBlock(blkStart, blkStart + 1); 513 } else { 514 wordFound = true; 515 } 516 } 517 offset++; 518 } 519 } else { if (ch == chars[stringInd]) { stringInd++; 522 if (stringInd == chars.length) { if (offset == limitOffset) { 524 int blkEnd = initOffset + 1; 525 addBlock(blkEnd - stringInd, blkEnd); 526 } else { 527 wordFound = true; 528 } 529 } 530 offset++; 531 } else { offset += 1 - stringInd; 533 stringInd = 0; 534 insideWord = firstCharWordPart; 535 } 536 } 537 538 } 539 return offset; 540 } 541 542 } 543 544 545 546 private static final class StringBlocksFinder 547 extends AbstractBlocksFinder { 548 549 char chars[]; 550 551 int stringInd; 552 553 boolean matchCase; 554 555 public StringBlocksFinder() { 556 } 557 558 public void setParams(String s, boolean matchCase){ 559 this.matchCase = matchCase; 560 chars = (matchCase ? s : s.toLowerCase()).toCharArray(); 561 } 562 563 public void reset() { 564 super.reset(); 565 stringInd = 0; 566 } 567 568 public int find(int initOffset, CharSequence data) { 569 int offset = 0; 570 int endPos = data.length(); 571 while (offset >= 0 && offset < endPos) { 572 char ch = data.charAt(offset); 573 574 if (!matchCase) { 575 ch = Character.toLowerCase(ch); 576 } 577 if (ch == chars[stringInd]) { 578 579 stringInd++; 580 if (stringInd == chars.length) { 581 int blkEnd = initOffset + offset + 1; 582 addBlock(blkEnd - stringInd, blkEnd); 583 stringInd = 0; 584 } 585 offset++; 586 } else { 587 offset += 1 - stringInd; 588 stringInd = 0; 589 } 590 591 } 592 return offset; 593 } 594 595 } 596 597 598 private static final class WholeWordsBwdFinder extends GenericBwdFinder 599 implements StringFinder { 600 601 char chars[]; 602 603 int stringInd; 604 605 boolean matchCase; 606 607 boolean insideWord; 608 609 boolean lastCharWordPart; 610 611 boolean wordFound; 612 613 int endInd; 614 615 Document doc; 616 617 public WholeWordsBwdFinder() { 618 } 619 620 public void setParams(Document doc, String s, boolean matchCase){ 621 this.doc = doc; 622 this.matchCase = matchCase; 623 chars = (matchCase ? s : s.toLowerCase()).toCharArray(); 624 endInd = chars.length - 1; 625 DocUtils.isIdentifierPart(doc, chars[endInd]); 626 } 627 628 public int getFoundLength() { 629 return chars.length; 630 } 631 632 public void reset() { 633 super.reset(); 634 insideWord = false; 635 wordFound = false; 636 stringInd = endInd; 637 } 638 639 protected int scan(char ch, boolean lastChar) { 640 if (!matchCase) { 641 ch = Character.toLowerCase(ch); 642 } 643 644 if (wordFound) { 646 if (DocUtils.isIdentifierPart(doc, ch)) { wordFound = false; 648 insideWord = lastCharWordPart; 649 stringInd = endInd; 650 return endInd; 651 } else { 652 found = true; 653 return 1; 654 } 655 } 656 657 if (stringInd == endInd) { if (ch != chars[endInd] || insideWord) { insideWord = DocUtils.isIdentifierPart(doc, ch); 660 return -1; 661 } else { stringInd = endInd - 1; if (chars.length == 1) { 664 if (lastChar) { 665 found = true; 666 return 0; 667 } else { 668 wordFound = true; 669 return -1; 670 } 671 } 672 return -1; 673 } 674 } else { if (ch == chars[stringInd]) { stringInd--; 677 if (stringInd == -1) { if (lastChar) { 679 found = true; 680 return 0; 681 } else { 682 wordFound = true; 683 return -1; 684 } 685 } 686 return -1; } else { int back = chars.length - 2 - stringInd; 689 stringInd = endInd; 690 insideWord = lastCharWordPart; 691 return back; 692 } 693 } 694 } 695 } 696 697 698 699 private static abstract class GenericFwdFinder extends AbstractFinder { 700 701 public final int find(int initOffset, CharSequence chars) { 702 int offset = 0; 703 int limitPos = chars.length(); 704 int limitOffset = limitPos - 1; 705 while (offset >= 0 && offset < limitPos) { 706 offset += scan(chars.charAt(offset), (offset == limitOffset)); 707 if (found) { 708 break; 709 } 710 } 711 return offset; 712 } 713 714 727 protected abstract int scan(char ch, boolean lastChar); 728 729 } 730 731 732 private static abstract class GenericBwdFinder extends AbstractFinder { 733 734 public final int find(int initOffset, CharSequence chars) { 735 int offset = chars.length() - 1; 736 int offset2; 737 int limitPos = 0; 738 int limitOffset = chars.length(); 739 while (offset >= 0 && offset < limitOffset) { 740 offset += scan(chars.charAt(offset), (offset == limitOffset)); 741 if (found) { 742 break; 743 } 744 } 745 return offset; 746 } 747 748 761 protected abstract int scan(char ch, boolean lastChar); 762 763 } 764 765 766 private static final class WholeWordsFwdFinder extends GenericFwdFinder 767 implements StringFinder { 768 769 char chars[]; 770 771 int stringInd; 772 773 boolean matchCase; 774 775 Document doc; 776 777 boolean insideWord; 778 779 boolean firstCharWordPart; 780 781 boolean wordFound; 782 783 public WholeWordsFwdFinder() { 784 } 785 786 public void setParams(Document doc, String s, boolean matchCase){ 787 this.doc = doc; 788 this.matchCase = matchCase; 789 chars = (matchCase ? s : s.toLowerCase()).toCharArray(); 790 firstCharWordPart = DocUtils.isIdentifierPart(doc, chars[0]); 791 } 792 793 public int getFoundLength() { 794 return chars.length; 795 } 796 797 public void reset() { 798 super.reset(); 799 insideWord = false; 800 wordFound = false; 801 stringInd = 0; 802 } 803 804 protected int scan(char ch, boolean lastChar) { 805 if (!matchCase) { 806 ch = Character.toLowerCase(ch); 807 } 808 809 if (wordFound) { 811 if (DocUtils.isIdentifierPart(doc, ch)) { wordFound = false; 813 insideWord = firstCharWordPart; 814 stringInd = 0; 815 return 1 - chars.length; 816 } else { 817 found = true; 818 return -chars.length; 819 } 820 } 821 822 if (stringInd == 0) { if (ch != chars[0] || insideWord) { insideWord = DocUtils.isIdentifierPart(doc, ch); 825 return 1; 826 } else { stringInd = 1; if (chars.length == 1) { 829 if (lastChar) { 830 found = true; 831 return 0; 832 } else { 833 wordFound = true; 834 return 1; 835 } 836 } 837 return 1; 838 } 839 } else { if (ch == chars[stringInd]) { stringInd++; 842 if (stringInd == chars.length) { if (lastChar) { 844 found = true; 845 return 1 - chars.length; } else { 847 wordFound = true; 848 return 1; 849 } 850 } 851 return 1; } else { int back = 1 - stringInd; 854 stringInd = 0; 855 insideWord = firstCharWordPart; 856 return back; } 858 } 859 } 860 861 } 862 863 private static class StringBwdFinder extends GenericBwdFinder 864 implements StringFinder { 865 866 char chars[]; 867 868 int stringInd; 869 870 boolean matchCase; 871 872 int endInd; 873 874 public StringBwdFinder() { 875 } 876 877 public void setParams(String s, boolean matchCase){ 878 this.matchCase = matchCase; 879 chars = (matchCase ? s : s.toLowerCase()).toCharArray(); 880 endInd = chars.length - 1; 881 } 882 883 public int getFoundLength() { 884 return chars.length; 885 } 886 887 public void reset() { 888 super.reset(); 889 stringInd = endInd; 890 } 891 892 protected int scan(char ch, boolean lastChar) { 893 if (!matchCase) { 894 ch = Character.toLowerCase(ch); 895 } 896 if (ch == chars[stringInd]) { 897 stringInd--; 898 if (stringInd == -1) { 899 found = true; 900 return 0; 901 } 902 return -1; 903 } else { 904 if (stringInd == endInd) { 905 return -1; 906 } else { 907 int back = chars.length - 2 - stringInd; 908 stringInd = endInd; 909 return back; 910 } 911 } 912 } 913 914 } 915 916 private static final class StringFwdFinder extends GenericFwdFinder 917 implements StringFinder { 918 919 char chars[]; 920 921 int stringInd; 922 923 boolean matchCase; 924 925 public StringFwdFinder() { 926 } 927 928 public void setParams(String s, boolean matchCase){ 929 this.matchCase = matchCase; 930 chars = (matchCase ? s : s.toLowerCase()).toCharArray(); 931 } 932 933 public int getFoundLength() { 934 return chars.length; 935 } 936 937 public void reset() { 938 super.reset(); 939 stringInd = 0; 940 } 941 942 protected int scan(char ch, boolean lastChar) { 943 if (!matchCase) { 944 ch = Character.toLowerCase(ch); 945 } 946 if (ch == chars[stringInd]) { 947 stringInd++; 948 if (stringInd == chars.length) { found = true; 950 return 1 - stringInd; } 952 return 1; } else { 954 if (stringInd == 0) { 955 return 1; 956 } else { 957 int back = 1 - stringInd; 958 stringInd = 0; 959 return back; 960 } 961 } 962 } 963 964 } 965 966 967 private abstract static class RegExpFinder extends AbstractFinder implements StringFinder{ 968 public abstract Matcher getMatcher(); 969 } 970 971 private static class RegExpBwdFinder extends RegExpFinder{ 973 974 boolean matchCase; 975 Pattern pattern; 976 int length = 0; 977 Matcher matcher; 978 979 980 public RegExpBwdFinder() { 981 } 982 983 public Matcher getMatcher(){ 984 return matcher; 985 } 986 987 public void setParams(Pattern pattern, boolean matchCase){ 988 this.matchCase = matchCase; 989 this.pattern = pattern; 990 } 991 992 public int getFoundLength() { 993 return length; 994 } 995 996 public void reset() { 997 super.reset(); 998 length = 0; 999 } 1000 1001 private int lineFind (int lineStart, int lineEnd, CharSequence chars){ 1002 matcher = pattern.matcher(chars.subSequence(lineStart, lineEnd)); 1003 int ret = -1; 1004 while (matcher.find()){ 1005 int start = matcher.start(); 1006 int end = matcher.end(); 1007 length = end - start; 1008 if (length <= 0){ 1009 found = false; 1010 return -1; 1011 } 1012 ret = start; 1013 } 1014 return ret; 1015 } 1016 1017 public int find(int initOffset, CharSequence chars) { 1018 char ch; 1019 1020 int charsEnd = chars.length() - 1; 1021 int lineEnd = charsEnd; 1022 int lineStart = charsEnd; 1023 for (int i = charsEnd; i>=0; i--){ 1024 ch = chars.charAt(i); 1025 if (ch == '\n' || i==0){ 1026 int retFind = lineFind (lineStart+((i==0)?0:1), lineEnd+1, chars); 1027 if (retFind!=-1){ 1028 found = true; 1029 return i + retFind + ((i==0)?0:1); 1030 } 1031 lineStart--; 1032 lineEnd = lineStart; 1033 }else{ 1034 lineStart--; 1035 } 1036 } 1037 return -1; 1038 } 1039 1040 } 1041 1042 private static final class RegExpFwdFinder extends RegExpFinder{ 1043 1044 Pattern pattern; 1045 boolean matchCase; 1046 int length = 0; 1047 Matcher matcher; 1048 1049 public RegExpFwdFinder() { 1050 } 1051 1052 public Matcher getMatcher(){ 1053 return matcher; 1054 } 1055 1056 public void setParams(Pattern pattern, boolean matchCase){ 1057 this.matchCase = matchCase; 1058 this.pattern = pattern; 1059 } 1060 1061 public int getFoundLength() { 1062 return length; 1063 } 1064 1065 public void reset() { 1066 super.reset(); 1067 length = 0; 1068 } 1069 1070 public int find(int initOffset, CharSequence chars) { 1071 matcher = pattern.matcher(chars); 1072 if (matcher.find()){ 1073 found = true; 1074 int start = matcher.start(); 1075 int end = matcher.end(); 1076 length = end - start; 1077 if (length <= 0){ 1078 found = false; 1079 return -1; 1080 } 1081 return start; 1082 }else{ 1083 return -1; 1084 } 1085 1086 } 1087 } 1088 1089 1090 private static final class RegExpBlocksFinder 1091 extends AbstractBlocksFinder { 1092 1093 Pattern pattern; 1094 1095 int stringInd; 1096 1097 boolean matchCase; 1098 1099 public RegExpBlocksFinder() { 1100 } 1101 1102 public void setParams(Pattern pattern, boolean matchCase){ 1103 this.pattern = pattern; 1104 this.matchCase = matchCase; 1105 } 1106 1107 public void reset() { 1108 super.reset(); 1109 stringInd = 0; 1110 } 1111 1112 public int find(int initOffset, CharSequence data) { 1113 Matcher matcher = pattern.matcher(data); 1114 int ret = 0; 1115 while (matcher.find()){ 1116 int start = initOffset + matcher.start(); 1117 int end = initOffset + matcher.end(); 1118 addBlock(start, end); 1119 ret = start; 1120 } 1121 return ret; 1122 } 1123 1124 } 1125 1126 private static class PatternCache{ 1127 1128 private static String cache_str; 1129 private static boolean cache_matchCase; 1130 private static Pattern cache_pattern; 1131 1132 private PatternCache(){ 1133 } 1134 1135 public static void putPattern(String str, boolean matchCase, Pattern pattern){ 1136 cache_str = str; 1137 cache_matchCase = matchCase; 1138 cache_pattern = pattern; 1139 } 1140 1141 public static Pattern getPattern(String str, boolean matchCase){ 1142 if (str == null) return null; 1143 if (str.equals(cache_str) && matchCase == cache_matchCase){ 1144 return cache_pattern; 1145 } 1146 return null; 1147 } 1148 1149 public static void clear(){ 1150 cache_str = null; 1151 cache_matchCase = false; 1152 cache_pattern = null; 1153 } 1154 } 1155 1156 public static class FindReplaceResult{ 1157 private int[] positions; 1158 private String replacedString; 1159 1160 public FindReplaceResult(int[] positions, String replacedString){ 1161 this.positions = positions; 1162 this.replacedString = replacedString; 1163 } 1164 1165 public String getReplacedString(){ 1166 return replacedString; 1167 } 1168 1169 public int[] getFoundPositions(){ 1170 return positions; 1171 } 1172 } 1173 1174} 1175 1176 1177 | Popular Tags |