| 626 | } |
| 627 | |
| 628 | func (d *Differ) FancyReplace(a []string, alo int, ahi int, b []string, blo int, bhi int) (out []string, err error) { |
| 629 | // When replacing one block of lines with another, search the blocks |
| 630 | // for *similar* lines; the best-matching pair (if any) is used as a |
| 631 | // synch point, and intraline difference marking is done on the |
| 632 | // similar pair. Lots of work, but often worth it. |
| 633 | |
| 634 | // don't synch up unless the lines have a similarity score of at |
| 635 | // least cutoff; best_ratio tracks the best score seen so far |
| 636 | best_ratio := 0.74 |
| 637 | cutoff := 0.75 |
| 638 | cruncher := NewMatcherWithJunk(a, b, true, d.Charjunk) |
| 639 | eqi := -1 // 1st indices of equal lines (if any) |
| 640 | eqj := -1 |
| 641 | out = []string{} |
| 642 | |
| 643 | // search for the pair that matches best without being identical |
| 644 | // (identical lines must be junk lines, & we don't want to synch up |
| 645 | // on junk -- unless we have to) |
| 646 | var best_i, best_j int |
| 647 | for j := blo; j < bhi; j++ { |
| 648 | bj := b[j] |
| 649 | cruncher.SetSeq2(listifyString(bj)) |
| 650 | for i := alo; i < ahi; i++ { |
| 651 | ai := a[i] |
| 652 | if ai == bj { |
| 653 | if eqi == -1 { |
| 654 | eqi = i |
| 655 | eqj = j |
| 656 | } |
| 657 | continue |
| 658 | } |
| 659 | cruncher.SetSeq1(listifyString(ai)) |
| 660 | // computing similarity is expensive, so use the quick |
| 661 | // upper bounds first -- have seen this speed up messy |
| 662 | // compares by a factor of 3. |
| 663 | // note that ratio() is only expensive to compute the first |
| 664 | // time it's called on a sequence pair; the expensive part |
| 665 | // of the computation is cached by cruncher |
| 666 | if cruncher.RealQuickRatio() > best_ratio && |
| 667 | cruncher.QuickRatio() > best_ratio && |
| 668 | cruncher.Ratio() > best_ratio { |
| 669 | best_ratio = cruncher.Ratio() |
| 670 | best_i = i |
| 671 | best_j = j |
| 672 | } |
| 673 | } |
| 674 | } |
| 675 | if best_ratio < cutoff { |
| 676 | // no non-identical "pretty close" pair |
| 677 | if eqi == -1 { |
| 678 | // no identical pair either -- treat it as a straight replace |
| 679 | out, _ = d.PlainReplace(a, alo, ahi, b, blo, bhi) |
| 680 | return out, nil |
| 681 | } |
| 682 | // no close pair, but an identical pair -- synch up on that |
| 683 | best_i = eqi |
| 684 | best_j = eqj |
| 685 | best_ratio = 1.0 |