1 21 22 package org.armedbear.j; 23 24 import gnu.regexp.RE; 25 import gnu.regexp.REException; 26 import gnu.regexp.REMatch; 27 28 public class Search implements Cloneable 29 { 30 private String pattern; 31 private String lowerCasePattern; 32 private int patternLength; 33 34 private RE re; 35 private REMatch match; 36 37 private boolean ignoreCase; 38 private boolean wholeWordsOnly; 39 private boolean regularExpression; 40 private boolean isMultilinePattern; 41 private boolean restrictToSelection; 42 43 private Region region; 44 45 public Search() 46 { 47 setPattern(new String ()); 48 } 49 50 public Search(String pattern, boolean ignoreCase, boolean wholeWordsOnly) 51 { 52 setPattern(pattern); 53 this.ignoreCase = ignoreCase; 54 this.wholeWordsOnly = wholeWordsOnly; 55 } 56 57 public final String getPattern() 58 { 59 return pattern; 60 } 61 62 public final void setPattern(String s) 63 { 64 if (s != null) { 65 pattern = s; 66 lowerCasePattern = s.toLowerCase(); 67 patternLength = s.length(); 68 } else { 69 pattern = lowerCasePattern = ""; 70 patternLength = 0; 71 } 72 } 73 74 public final void appendCharToPattern(char c) 75 { 76 pattern += c; 77 lowerCasePattern = pattern.toLowerCase(); 78 ++patternLength; 79 } 80 81 public final int getPatternLength() 82 { 83 return patternLength; 84 } 85 86 public final String getLowerCasePattern() 87 { 88 return lowerCasePattern; 89 } 90 91 public final RE getRE() 92 { 93 return re; 94 } 95 96 public final void setRE(RE re) 97 { 98 this.re = re; 99 } 100 101 public final REMatch getMatch() 102 { 103 return match; 104 } 105 106 public final boolean ignoreCase() 107 { 108 return ignoreCase; 109 } 110 111 public final void setIgnoreCase(boolean b) 112 { 113 ignoreCase = b; 114 } 115 116 public final boolean wholeWordsOnly() 117 { 118 return wholeWordsOnly; 119 } 120 121 public final void setWholeWordsOnly(boolean b) 122 { 123 wholeWordsOnly = b; 124 } 125 126 public final boolean isRegularExpression() 127 { 128 return regularExpression; 129 } 130 131 public final void setRegularExpression(boolean b) 132 { 133 regularExpression = b; 134 } 135 136 public final boolean isMultilinePattern() 137 { 138 return isMultilinePattern; 139 } 140 141 public final void setMultiline(boolean b) 142 { 143 isMultilinePattern = b; 144 } 145 146 public final boolean restrictToSelection() 147 { 148 return restrictToSelection; 149 } 150 151 public final void setRestrictToSelection(boolean b) 152 { 153 restrictToSelection = b; 154 } 155 156 public final Region getRegion() 157 { 158 return region; 159 } 160 161 public final void setRegion(Region r) 162 { 163 region = r; 164 } 165 166 protected Position findInBuffer(Buffer buffer) 167 { 168 return find(buffer, new Position(buffer.getFirstLine(), 0)); 169 } 170 171 public final Position find(Buffer buffer, Position start) 172 { 173 return regularExpression ? findRegExp(buffer, start) : findString(buffer, start); 174 } 175 176 public final Position reverseFind(Buffer buffer, Position start) 177 { 178 if (regularExpression) { 179 if (isMultilinePattern) 180 return reverseFindMultilineRegExp(buffer, start); 181 else 182 return reverseFindRegExp(buffer, start); 183 } else 184 return reverseFindString(buffer, start); 185 } 186 187 public final Position find(Mode mode, Position start) 188 { 189 return regularExpression ? findRegExp(mode, start) : findString(mode, start); 190 } 191 192 public final Position findInLine(Mode mode, Position start) 193 { 194 if (regularExpression) 195 return findRegExpInLine(mode, start.getLine(), start.getOffset(), 196 start.getLineLength()); 197 else 198 return findStringInLine(mode, start.getLine(), start.getOffset(), 199 start.getLineLength()); 200 } 201 202 public final boolean find(String s) 203 { 204 return regularExpression ? findRegExp(s) : findString(s); 205 } 206 207 public final boolean findDelimited(String s, Mode mode) 208 { 209 return regularExpression ? findRegExpDelimited(s, mode) : findStringDelimited(s, mode); 210 } 211 212 public final Position findString(Buffer buffer, Position start) 215 { 216 return findString(buffer.getMode(), start); 217 } 218 219 private Position findString(Mode mode, Position start) 222 { 223 Debug.assertTrue(lowerCasePattern.equals(pattern.toLowerCase())); 224 Debug.assertTrue(patternLength == pattern.length()); 225 Line line = start.getLine(); 226 int begin = start.getOffset(); 227 Line endLine; 228 if (restrictToSelection && region != null) 229 endLine = region.getEndLine(); 230 else 231 endLine = null; 232 Position pos = null; 233 while (line != endLine) { 234 pos = findStringInLine(mode, line, begin, line.length()); 235 if (pos != null) 236 return pos; 237 line = line.next(); 238 begin = 0; 239 } 240 if (line != null) { 241 pos = findStringInLine(mode, line, begin, region.getEnd().getOffset()); 243 } 244 return pos; 245 } 246 247 public Position findString(Buffer buffer, Position start, boolean wrapBuffer) 249 { 250 Debug.assertTrue(lowerCasePattern.equals(pattern.toLowerCase())); 251 Debug.assertTrue(patternLength == pattern.length()); 252 Mode mode = buffer.getMode(); 253 Line line = start.getLine(); 254 int begin = start.getOffset(); 255 while (line != null) { 256 Position pos = findStringInLine(mode, line, begin, line.length()); 257 if (pos != null) 258 return pos; 259 line = line.next(); 260 begin = 0; 261 } 262 if (wrapBuffer) { 263 line = buffer.getFirstLine(); 264 Line endLine = start.getNextLine(); 265 while (line != endLine) { 266 Position pos = findStringInLine(mode, line, 0, line.length()); 267 if (pos != null) 268 return pos; 269 line = line.next(); 270 } 271 } 272 return null; 273 } 274 275 private Position findStringInLine(Mode mode, Line line, int begin, int end) 276 { 277 String toBeSearched; 278 if (end < line.length()) 279 toBeSearched = line.substring(0, end); 280 else 281 toBeSearched = line.getText(); 282 int index = begin; 283 int limit = end - patternLength; 284 while (index <= limit) { 285 if (ignoreCase) 286 index = toBeSearched.toLowerCase().indexOf(lowerCasePattern, index); 287 else 288 index = toBeSearched.indexOf(pattern, index); 289 if (index < 0) 290 break; 291 Position pos = new Position(line, index); 292 if (!wholeWordsOnly || Utilities.isDelimited(mode, pos, patternLength)) 293 return pos; 294 ++index; 295 } 296 return null; 297 } 298 299 private boolean findString(String s) 300 { 301 Debug.assertTrue(patternLength == pattern.length()); 302 int index = 0; 303 int limit = s.length() - patternLength; 304 while (index <= limit) { 305 if (ignoreCase) 306 index = s.toLowerCase().indexOf(lowerCasePattern, index); 307 else 308 index = s.indexOf(pattern, index); 309 if (index < 0) 310 break; 311 if (!wholeWordsOnly || Utilities.isDelimited(s, index, patternLength)) 312 return true; 313 ++index; 314 } 315 return false; 316 } 317 318 private boolean findStringDelimited(String s, Mode mode) 319 { 320 Debug.assertTrue(wholeWordsOnly); 321 Debug.assertTrue(patternLength == pattern.length()); 322 int index = 0; 323 int limit = s.length() - patternLength; 324 while (index <= limit) { 325 if (ignoreCase) 326 index = s.toLowerCase().indexOf(lowerCasePattern, index); 327 else 328 index = s.indexOf(pattern, index); 329 if (index < 0) 330 break; 331 if (Utilities.isDelimited(s, index, patternLength, mode)) 332 return true; 333 ++index; 334 } 335 return false; 336 } 337 338 public Position reverseFindString(Buffer buffer, Position start) 340 { 341 Debug.assertTrue(lowerCasePattern.equals(pattern.toLowerCase())); 342 Debug.assertTrue(patternLength == pattern.length()); 343 Line line = start.getLine(); 344 Position pos = reverseFindStringInLine(buffer, line, 0, start.getOffset()); 345 if (pos != null) 346 return pos; 347 line = line.previous(); 348 while (line != null) { 349 pos = reverseFindStringInLine(buffer, line, 0, line.length()); 350 if (pos != null) 351 return pos; 352 line = line.previous(); 353 } 354 return null; 355 } 356 357 private Position reverseFindStringInLine(Buffer buffer, Line line, int begin, int end) 358 { 359 int index = end; 360 while (index >= begin) { 361 if (ignoreCase) 362 index = line.getText().toLowerCase().lastIndexOf(lowerCasePattern, index); 363 else 364 index = line.getText().lastIndexOf(pattern, index); 365 if (index < 0) 366 break; 367 Position pos = new Position(line, index); 368 if (!wholeWordsOnly || Utilities.isDelimited(buffer, pos, patternLength)) 369 return pos; 370 --index; 371 } 372 return null; 373 } 374 375 public final Position findRegExp(Buffer buffer, Position start) 378 { 379 if (isMultilinePattern) 380 return findMultilineRegExp(buffer, start); 381 else 382 return findRegExp(buffer.getMode(), start); 383 } 384 385 public void setREFromPattern() throws REException 386 { 387 int cflags = 0; 388 if (isMultilinePattern) 389 cflags |= RE.REG_MULTILINE; 390 if (ignoreCase) 391 cflags |= RE.REG_ICASE; 392 re = new RE(pattern, cflags); 393 } 394 395 private Position findMultilineRegExp(Buffer buffer, Position start) 398 { 399 if (re == null) { 400 try { 401 setREFromPattern(); 402 } 403 catch (Throwable t) { 404 Log.error(t); 405 return null; 406 } 407 } 408 final String s = buffer.getText(); 409 int startIndex = buffer.getAbsoluteOffset(start); 410 int endIndex = -1; 411 if (restrictToSelection && region != null) 412 endIndex = buffer.getAbsoluteOffset(region.getEnd()); 413 while (true) { 414 match = findMatch(s, startIndex, endIndex); 415 if (match == null) 416 return null; 417 if (!wholeWordsOnly) 418 break; 419 if (Utilities.isDelimited(buffer.getMode(), s, 420 match.getStartIndex(), match.getEndIndex())) 421 break; 422 startIndex = match.getStartIndex() + 1; 423 } 424 return buffer.getPosition(match.getStartIndex()); 425 } 426 427 private Position reverseFindMultilineRegExp(Buffer buffer, Position start) 428 { 429 if (re == null) { 430 try { 431 setREFromPattern(); 432 } 433 catch (Throwable t) { 434 Log.error(t); 435 return null; 436 } 437 } 438 int startIndex = 0; 439 int endIndex = buffer.getAbsoluteOffset(start); 440 final String s = buffer.getText().substring(0, endIndex); 441 REMatch lastMatch = null; 442 while (true) { 443 match = findMatch(s, startIndex, -1); 444 if (match == null) 445 break; 446 if (!wholeWordsOnly) 447 lastMatch = match; 448 else if (Utilities.isDelimited(buffer.getMode(), s, 449 match.getStartIndex(), 450 match.getEndIndex())) 451 lastMatch = match; 452 startIndex = match.getStartIndex() + 1; 453 } 454 if (lastMatch == null) 455 return null; 456 match = lastMatch; 457 return buffer.getPosition(match.getStartIndex()); 458 } 459 460 private REMatch findMatch(String s, int startIndex, int endIndex) 462 { 463 REMatch m = re.getMatch(s, startIndex); 464 if (m == null) 465 return null; if (endIndex >= 0 && m.getEndIndex() > endIndex) 467 return null; return m; 469 } 470 471 private Position findRegExp(Mode mode, Position start) 474 { 475 if (re == null) { 476 try { 477 setREFromPattern(); 478 } 479 catch (Throwable t) { 480 Log.error(t); 481 return null; 482 } 483 } 484 match = null; 485 Line line = start.getLine(); 486 int begin = start.getOffset(); 487 Line endLine; 488 if (restrictToSelection && region != null) 489 endLine = region.getEndLine(); 490 else 491 endLine = null; 492 Position pos = null; 493 while (line != endLine) { 494 pos = findRegExpInLine(mode, line, begin, line.length()); 495 if (pos != null) 496 return pos; 497 line = line.next(); 498 begin = 0; 499 } 500 if (line != null) { 501 pos = findRegExpInLine(mode, line, begin, region.getEndOffset()); 503 } 504 return pos; 505 } 506 507 private Position findRegExpInLine(Mode mode, Line line, int begin, int end) 508 { 509 String toBeSearched; 510 if (end < line.length()) 511 toBeSearched = line.substring(0, end); 512 else 513 toBeSearched = line.getText(); 514 int index = begin; 515 int limit = toBeSearched.length(); 516 while (index <= limit) { 517 match = re.getMatch(toBeSearched, index); 518 if (match == null) 519 break; 520 Position pos = new Position(line, match.getStartIndex()); 521 if (!wholeWordsOnly || Utilities.isDelimited(mode, pos, match.toString().length())) 522 return pos; 523 index = match.getStartIndex() + 1; 524 } 525 return null; 526 } 527 528 private boolean findRegExp(String toBeSearched) 529 { 530 int index = 0; 531 int limit = toBeSearched.length(); 532 while (index <= limit) { 533 match = re.getMatch(toBeSearched, index); 534 if (match == null) 535 break; 536 if (!wholeWordsOnly || Utilities.isDelimited(toBeSearched, match.getStartIndex(), match.toString().length())) 537 return true; 538 index = match.getStartIndex() + 1; 539 } 540 return false; 541 } 542 543 private boolean findRegExpDelimited(String s, Mode mode) 544 { 545 Debug.assertTrue(wholeWordsOnly); 546 int index = 0; 547 int limit = s.length(); 548 while (index <= limit) { 549 match = re.getMatch(s, index); 550 if (match == null) 551 break; 552 if (Utilities.isDelimited(s, match.getStartIndex(), match.toString().length(), mode)) 553 return true; 554 index = match.getStartIndex() + 1; 555 } 556 return false; 557 } 558 559 public Position reverseFindRegExp(Buffer buffer, Position start) 561 { 562 if (re == null) { 563 try { 564 re = new RE(pattern, ignoreCase ? RE.REG_ICASE : 0); 565 } 566 catch (Throwable t) { 567 Log.error(t); 568 return null; 569 } 570 } 571 Line line = start.getLine(); 572 match = null; 573 Position pos = reverseFindRegExpInLine(buffer, line, 0, start.getOffset()); 574 if (pos != null) 575 return pos; 576 line = line.previous(); 577 while (line != null) { 578 pos = reverseFindRegExpInLine(buffer, line, 0, line.length()); 579 if (pos != null) 580 return pos; 581 line = line.previous(); 582 } 583 return null; 584 } 585 586 private Position reverseFindRegExpInLine(Buffer buffer, Line line, int begin, int end) 587 { 588 int index = end; 589 while (index >= begin) { 590 match = re.getMatch(line.getText(), index); 591 if (match != null && match.getStartIndex() <= end) { 592 Position pos = new Position(line, match.getStartIndex()); 593 if (!wholeWordsOnly || Utilities.isDelimited(buffer, pos, match.toString().length())) 594 return pos; 595 } 596 --index; 597 } 598 return null; 599 } 600 601 public void notFound(Editor editor) 602 { 603 FastStringBuffer sb = new FastStringBuffer(); 604 if (regularExpression) 605 sb.append("Regular expression "); 606 sb.append('"'); 607 sb.append(pattern); 608 sb.append("\" not found"); 609 editor.status(sb.toString()); 610 } 611 612 public boolean equals(Object object) 613 { 614 if (this == object) 615 return true; 616 if (object instanceof Search) { 617 Search search = (Search) object; 618 if (pattern == null) { 619 if (search.pattern != null) 620 return false; 621 } else { 622 if (!pattern.equals(search.pattern)) 624 return false; 625 } 626 if (ignoreCase != search.ignoreCase) 627 return false; 628 if (wholeWordsOnly != search.wholeWordsOnly) 629 return false; 630 if (regularExpression != search.regularExpression) 631 return false; 632 if (restrictToSelection != search.restrictToSelection) 633 return false; 634 return true; 636 } 637 return false; 638 } 639 640 public Object clone() 641 { 642 try { 643 return super.clone(); 644 } 645 catch (CloneNotSupportedException e) { 646 throw new InternalError (e.toString()); 647 } 648 } 649 } 650 | Popular Tags |