1 7 package com.ibm.icu.text; 8 9 import com.ibm.icu.impl.Utility; 10 11 44 class TransliterationRule { 45 46 52 56 private StringMatcher anteContext; 57 58 61 private StringMatcher key; 62 63 67 private StringMatcher postContext; 68 69 73 private UnicodeReplacer output; 74 75 82 private String pattern; 83 84 91 UnicodeMatcher[] segments; 92 93 98 private int anteContextLength; 99 100 104 private int keyLength; 105 106 109 byte flags; 110 111 114 static final int ANCHOR_START = 1; 115 static final int ANCHOR_END = 2; 116 117 121 private final RuleBasedTransliterator.Data data; 122 123 124 private static final String COPYRIGHT = 125 "\u00A9 IBM Corporation 1999-2001. All rights reserved."; 126 127 155 public TransliterationRule(String input, 156 int anteContextPos, int postContextPos, 157 String output, 158 int cursorPos, int cursorOffset, 159 UnicodeMatcher[] segs, 160 boolean anchorStart, boolean anchorEnd, 161 RuleBasedTransliterator.Data theData) { 162 data = theData; 163 164 if (anteContextPos < 0) { 166 anteContextLength = 0; 167 } else { 168 if (anteContextPos > input.length()) { 169 throw new IllegalArgumentException ("Invalid ante context"); 170 } 171 anteContextLength = anteContextPos; 172 } 173 if (postContextPos < 0) { 174 keyLength = input.length() - anteContextLength; 175 } else { 176 if (postContextPos < anteContextLength || 177 postContextPos > input.length()) { 178 throw new IllegalArgumentException ("Invalid post context"); 179 } 180 keyLength = postContextPos - anteContextLength; 181 } 182 if (cursorPos < 0) { 183 cursorPos = output.length(); 184 } else if (cursorPos > output.length()) { 185 throw new IllegalArgumentException ("Invalid cursor position"); 186 } 187 188 this.segments = segs; 193 194 pattern = input; 195 flags = 0; 196 if (anchorStart) { 197 flags |= ANCHOR_START; 198 } 199 if (anchorEnd) { 200 flags |= ANCHOR_END; 201 } 202 203 anteContext = null; 204 if (anteContextLength > 0) { 205 anteContext = new StringMatcher(pattern.substring(0, anteContextLength), 206 0, data); 207 } 208 209 key = null; 210 if (keyLength > 0) { 211 key = new StringMatcher(pattern.substring(anteContextLength, anteContextLength + keyLength), 212 0, data); 213 } 214 215 int postContextLength = pattern.length() - keyLength - anteContextLength; 216 postContext = null; 217 if (postContextLength > 0) { 218 postContext = new StringMatcher(pattern.substring(anteContextLength + keyLength), 219 0, data); 220 } 221 222 this.output = new StringReplacer(output, cursorPos + cursorOffset, data); 223 } 224 225 230 public int getAnteContextLength() { 231 return anteContextLength + (((flags & ANCHOR_START) != 0) ? 1 : 0); 232 } 233 234 240 final int getIndexValue() { 241 if (anteContextLength == pattern.length()) { 242 return -1; 245 } 246 int c = UTF16.charAt(pattern, anteContextLength); 247 return data.lookupMatcher(c) == null ? (c & 0xFF) : -1; 248 } 249 250 260 final boolean matchesIndexValue(int v) { 261 UnicodeMatcher m = (key != null) ? key : postContext; 264 return (m != null) ? m.matchesIndexValue(v) : true; 265 } 266 267 273 public boolean masks(TransliterationRule r2) { 274 306 307 311 312 int len = pattern.length(); 313 int left = anteContextLength; 314 int left2 = r2.anteContextLength; 315 int right = pattern.length() - left; 316 int right2 = r2.pattern.length() - left2; 317 318 321 if (left == left2 && right == right2 && 323 keyLength <= r2.keyLength && 324 r2.pattern.regionMatches(0, pattern, 0, len)) { 325 return (flags == r2.flags) || 327 (!((flags & ANCHOR_START) != 0) && !((flags & ANCHOR_END) != 0)) || 328 (((r2.flags & ANCHOR_START) != 0) && ((r2.flags & ANCHOR_END) != 0)); 329 } 330 331 return left <= left2 && 332 (right < right2 || 333 (right == right2 && keyLength <= r2.keyLength)) && 334 r2.pattern.regionMatches(left2 - left, pattern, 0, len); 335 } 336 337 static final int posBefore(Replaceable str, int pos) { 338 return (pos > 0) ? 339 pos - UTF16.getCharCount(str.char32At(pos-1)) : 340 pos - 1; 341 } 342 343 static final int posAfter(Replaceable str, int pos) { 344 return (pos >= 0 && pos < str.length()) ? 345 pos + UTF16.getCharCount(str.char32At(pos)) : 346 pos + 1; 347 } 348 349 370 public int matchAndReplace(Replaceable text, 371 Transliterator.Position pos, 372 boolean incremental) { 373 379 381 if (segments != null) { 383 for (int i=0; i<segments.length; ++i) { 384 ((StringMatcher) segments[i]).resetMatch(); 385 } 386 } 387 388 int keyLimit; 389 int[] intRef = new int[1]; 390 391 393 int oText; int minOText; 398 399 404 int anteLimit = posBefore(text, pos.contextStart); 405 406 int match; 407 408 intRef[0] = posBefore(text, pos.start); 410 411 if (anteContext != null) { 412 match = anteContext.matches(text, intRef, anteLimit, false); 413 if (match != UnicodeMatcher.U_MATCH) { 414 return UnicodeMatcher.U_MISMATCH; 415 } 416 } 417 418 oText = intRef[0]; 419 420 minOText = posAfter(text, oText); 421 422 424 if (((flags & ANCHOR_START) != 0) && oText != anteLimit) { 425 return UnicodeMatcher.U_MISMATCH; 426 } 427 428 430 intRef[0] = pos.start; 431 432 if (key != null) { 433 match = key.matches(text, intRef, pos.limit, incremental); 434 if (match != UnicodeMatcher.U_MATCH) { 435 return match; 436 } 437 } 438 439 keyLimit = intRef[0]; 440 441 if (postContext != null) { 442 if (incremental && keyLimit == pos.limit) { 443 return UnicodeMatcher.U_PARTIAL_MATCH; 448 } 449 450 match = postContext.matches(text, intRef, pos.contextLimit, incremental); 451 if (match != UnicodeMatcher.U_MATCH) { 452 return match; 453 } 454 } 455 456 oText = intRef[0]; 457 458 460 if (((flags & ANCHOR_END)) != 0) { 461 if (oText != pos.contextLimit) { 462 return UnicodeMatcher.U_MISMATCH; 463 } 464 if (incremental) { 465 return UnicodeMatcher.U_PARTIAL_MATCH; 466 } 467 } 468 469 471 474 int newLength = output.replace(text, pos.start, keyLimit, intRef); 475 int lenDelta = newLength - (keyLimit - pos.start); 476 int newStart = intRef[0]; 477 478 oText += lenDelta; 479 pos.limit += lenDelta; 480 pos.contextLimit += lenDelta; 481 pos.start = Math.max(minOText, Math.min(Math.min(oText, pos.limit), newStart)); 483 return UnicodeMatcher.U_MATCH; 484 } 485 486 490 public String toRule(boolean escapeUnprintable) { 491 493 StringBuffer rule = new StringBuffer (); 494 495 StringBuffer quoteBuf = new StringBuffer (); 499 500 boolean emitBraces = 503 (anteContext != null) || (postContext != null); 504 505 if ((flags & ANCHOR_START) != 0) { 507 rule.append('^'); 508 } 509 510 Utility.appendToRule(rule, anteContext, escapeUnprintable, quoteBuf); 512 513 if (emitBraces) { 514 Utility.appendToRule(rule, '{', true, escapeUnprintable, quoteBuf); 515 } 516 517 Utility.appendToRule(rule, key, escapeUnprintable, quoteBuf); 518 519 if (emitBraces) { 520 Utility.appendToRule(rule, '}', true, escapeUnprintable, quoteBuf); 521 } 522 523 Utility.appendToRule(rule, postContext, escapeUnprintable, quoteBuf); 524 525 if ((flags & ANCHOR_END) != 0) { 527 rule.append('$'); 528 } 529 530 Utility.appendToRule(rule, " > ", true, escapeUnprintable, quoteBuf); 531 532 534 Utility.appendToRule(rule, output.toReplacerPattern(escapeUnprintable), 535 true, escapeUnprintable, quoteBuf); 536 537 Utility.appendToRule(rule, ';', true, escapeUnprintable, quoteBuf); 538 539 return rule.toString(); 540 } 541 542 546 public String toString() { 547 return '{' + toRule(true) + '}'; 548 } 549 550 554 void addSourceSetTo(UnicodeSet toUnionTo) { 555 int limit = anteContextLength + keyLength; 556 for (int i=anteContextLength; i<limit; ) { 557 int ch = UTF16.charAt(pattern, i); 558 i += UTF16.getCharCount(ch); 559 UnicodeMatcher matcher = data.lookupMatcher(ch); 560 if (matcher == null) { 561 toUnionTo.add(ch); 562 } else { 563 matcher.addMatchSetTo(toUnionTo); 564 } 565 } 566 } 567 568 572 void addTargetSetTo(UnicodeSet toUnionTo) { 573 output.addReplacementSetTo(toUnionTo); 574 } 575 } 576 | Popular Tags |