1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 // MARKER(update_precomp.py): autogen include statement, do not remove 29 #include "precompiled_i18npool.hxx" 30 /************************************************************************* 31 32 Weighted Levenshtein Distance 33 including wildcards 34 '*' for any number (0 or more) of arbitrary characters 35 '?' for exactly one arbitrary character 36 escapeable with backslash, "\*" or "\?" 37 38 Return: 39 WLD if WLD <= nLimit, else nLimit+1 40 41 or, if bSplitCount: 42 WLD if WLD <= nLimit 43 -WLD if Replace and Insert and Delete <= nLimit 44 else nLimit+1 45 46 Recursive definition of WLD: 47 48 WLD( X(i), Y(j) ) = min( WLD( X(i-1), Y(j-1) ) + p(i,j) , 49 WLD( X(i) , Y(j-1) ) + q , 50 WLD( X(i-1), Y(j) ) + r ) 51 52 X(i) := the first i characters of the word X 53 Y(j) := the first j characters of the word Y 54 p(i,j) := 0 if i-th character of X == j-th character of Y, 55 p else 56 57 Boundary conditions: 58 WLD( X(0), Y(j) ) := j*q (Y created by j inserts) 59 WLD( X(i), Y(0) ) := i*r (Y created by i deletes) 60 WLD( X(0), Y(0) ) := 0 61 62 Instead of recursions a dynamic algorithm is used. 63 64 See also: German computer magazine 65 c't 07/89 pages 192-208 and c't 03/94 pages 230-239 66 67 *************************************************************************/ 68 69 70 #include <string.h> // strlen() 71 72 #if defined( _MSC_VER ) 73 #pragma warning(once: 4068) 74 #endif 75 76 #include "levdis.hxx" 77 78 79 #ifdef erTEST 80 #include <stdlib.h> 81 #include <stdio.h> 82 #include <iostream.h> 83 #endif 84 85 #ifdef SOLARIS 86 #undef min 87 #endif 88 89 #define LEVDISBIG (nLimit + 1) // Returnwert wenn Distanz > nLimit 90 #define LEVDISDOUBLEBUF 2048 // dadrueber wird nicht mehr gedoppelt 91 92 // Balance, aus Geschwindigkeitsgruenden ist dieses keine Funktion 93 // c == cpPattern[jj] == cString[ii] 94 // erst wird bis Fundstelle gesucht, wenn dort die Balance gleich ist, wird 95 // auch nach der Fundstelle verglichen 96 #define LEVDISBALANCE(jj,ii) \ 97 { \ 98 if ( jj != ii ) \ 99 { \ 100 register sal_Int32 k; \ 101 if ( jj > 0 ) \ 102 for ( k=0; k < jj; k++ ) \ 103 if ( cpPattern[k] == c ) \ 104 nBalance++; \ 105 if ( ii > 0 ) \ 106 for ( k=0; k < ii; k++ ) \ 107 if ( cString[k] == c ) \ 108 nBalance--; \ 109 if ( !nBalance ) \ 110 { \ 111 for ( k=jj+1; k < nPatternLen; k++ ) \ 112 if ( cpPattern[k] == c ) \ 113 nBalance++; \ 114 for ( k=ii+1; k < nStringLen; k++ ) \ 115 if ( cString[k] == c ) \ 116 nBalance--; \ 117 } \ 118 } \ 119 } 120 121 static sal_Int32 Impl_WLD_StringLen( const sal_Unicode* pStr ) 122 { 123 const sal_Unicode* pTempStr = pStr; 124 while( *pTempStr ) 125 pTempStr++; 126 return (sal_Int32)(pTempStr-pStr); 127 } 128 129 #ifdef erTESTMAT 130 #define erTESTMATMAX 180 131 static int npMatrix[erTESTMATMAX][erTESTMATMAX]; // nearly 64K 132 #endif 133 134 // Distanz von String zu Pattern 135 int WLevDistance::WLD( const sal_Unicode* cString, sal_Int32 nStringLen ) 136 { 137 int nSPMin = 0; // StrafPunkteMinimum 138 int nRepS = 0; // fuer SplitCount 139 140 #ifdef erTESTMAT 141 { 142 for ( sal_Int32 r=0; r<=nStringLen && r < erTESTMATMAX; r++ ) 143 for ( sal_Int32 c=0; c<=nPatternLen && c < erTESTMATMAX; c++ ) 144 npMatrix[r][c] = 99; // Matrix initialisieren, nur visuell 145 } 146 #endif 147 148 // Laengendifferenz von Pattern und String 149 int nLenDiff = nPatternLen - nStars - nStringLen; 150 // mehr Einfuegungen oder Loeschungen noetig als Limit? => raus hier 151 if ( (nLenDiff * nInsQ0 > nLimit) 152 || ((nStars == 0) && (nLenDiff * nDelR0 < -nLimit)) ) 153 return(LEVDISBIG); 154 155 // wenn der zu vergleichende String groesser ist als das bisherige Array 156 // muss dieses angepasst werden 157 if ( nStringLen >= nArrayLen ) 158 { 159 // gib ihm moeglichst mehr, damit nicht gleich naechstesmal 160 // wieder realloziert werden muss 161 if ( nStringLen < LEVDISDOUBLEBUF ) 162 nArrayLen = 2 * nStringLen; 163 else 164 nArrayLen = nStringLen + 1; 165 npDistance = aDisMem.NewMem( nArrayLen ); 166 #ifdef erTEST 167 if ( !npDistance ) 168 { 169 cerr << "DOOM! (Damned, Out Of Memory)" << endl; 170 exit(1); 171 } 172 #endif 173 } 174 175 // Anfangswerte der zweiten Spalte (erstes Pattern-Zeichen) berechnen 176 // die erste Spalte (0-Len Pattern) ist immer 0 .. nStringLen * nInsQ0, 177 // deren Minimum also 0 178 if ( nPatternLen == 0 ) 179 { 180 // Anzahl der Loeschungen, um auf Pattern zu kommen 181 for ( sal_Int32 i=0; i <= nStringLen; i++ ) 182 npDistance[i] = i * nDelR0; 183 } 184 else if ( cpPattern[0] == '*' && bpPatIsWild[0] ) 185 { 186 // statt einem '*' ist alles einsetzbar 187 for ( sal_Int32 i=0; i <= nStringLen; i++ ) 188 npDistance[i] = 0; 189 } 190 else 191 { 192 sal_Unicode c; 193 int nP; 194 c = cpPattern[0]; 195 if ( c == '?' && bpPatIsWild[0] ) 196 nP = 0; // ein '?' kann jedes Zeichen sein 197 else 198 // Minimum von Ersetzen und Loeschen+Einfuegen Gewichtung 199 nP = Min3( nRepP0, nRepP0, nDelR0 + nInsQ0 ); 200 npDistance[0] = nInsQ0; // mit einfachem Einfuegen geht's los 201 npDistance[1] = nInsQ0; 202 npDistance[2] = nInsQ0; 203 int nReplacePos = -1; // tristate Flag 204 int nDelCnt = 0; 205 for ( sal_Int32 i=1; i <= nStringLen; i++, nDelCnt += nDelR0 ) 206 { 207 if ( cString[i-1] == c ) 208 nP = 0; // Replace ab dieser Stelle ist 0 209 // Loeschungen um auf Pattern zu kommen + Replace 210 npDistance[i] = nDelCnt + nP; 211 if ( bSplitCount ) 212 { 213 if ( nReplacePos < 0 && nP ) 214 { // diese Stelle wird ersetzt 215 nRepS++; 216 nReplacePos = i; 217 #ifdef erTESTMAT 218 npMatrix[i][1] = -npDistance[i]; 219 #endif 220 } 221 else if ( nReplacePos > 0 && !nP ) 222 { 223 int nBalance = 0; // gleiche Anzahl c 224 LEVDISBALANCE( 0, i-1 ); 225 if ( !nBalance ) 226 { // einer wurde ersetzt, der ein Insert war 227 nRepS--; 228 #ifdef erTESTMAT 229 npMatrix[nReplacePos][1] = npDistance[nReplacePos]; 230 #endif 231 nReplacePos = 0; 232 } 233 } 234 } 235 } 236 nSPMin = Min3( npDistance[0], npDistance[1], npDistance[2] ); 237 } 238 #ifdef erTESTMAT 239 { 240 for ( sal_Int32 r=0; r<=nStringLen && r < erTESTMATMAX; r++ ) 241 { 242 npMatrix[r][0] = r * nInsQ0; 243 if ( npMatrix[r][1] >= 0) 244 npMatrix[r][1] = npDistance[r]; 245 } 246 } 247 #endif 248 249 // Distanzmatrix berechnen 250 sal_Int32 j = 0; // fuer alle Spalten des Pattern, solange nicht Limit 251 while ( (j < nPatternLen-1) 252 && nSPMin <= (bSplitCount ? 2 * nLimit : nLimit) ) 253 { 254 sal_Unicode c; 255 int nP, nQ, nR, nPij, d1, d2; 256 257 j++; 258 c = cpPattern[j]; 259 if ( bpPatIsWild[j] ) // '*' oder '?' nicht escaped 260 nP = 0; // kann ohne Strafpunkte ersetzt werden 261 else 262 nP = nRepP0; 263 if ( c == '*' && bpPatIsWild[j] ) 264 { 265 nQ = 0; // Einfuegen und Loeschen ohne Strafpunkte 266 nR = 0; 267 } 268 else 269 { 270 nQ = nInsQ0; // normale Gewichtung 271 nR = nDelR0; 272 } 273 d2 = npDistance[0]; 274 // Anzahl Einfuegungen um von Null-String auf Pattern zu kommen erhoehen 275 npDistance[0] = npDistance[0] + nQ; 276 nSPMin = npDistance[0]; 277 int nReplacePos = -1; // tristate Flag 278 // fuer jede Patternspalte den String durchgehen 279 for ( register sal_Int32 i=1; i <= nStringLen; i++ ) 280 { 281 d1 = d2; // WLD( X(i-1), Y(j-1) ) 282 d2 = npDistance[i]; // WLD( X(i) , Y(j-1) ) 283 if ( cString[i-1] == c ) 284 { 285 nPij = 0; // p(i,j) 286 if ( nReplacePos < 0 ) 287 { 288 int nBalance = 0; // gleiche Anzahl c 289 LEVDISBALANCE( j, i-1 ); 290 if ( !nBalance ) 291 nReplacePos = 0; // keine Ersetzung mehr 292 } 293 } 294 else 295 nPij = nP; 296 // WLD( X(i), Y(j) ) = min( WLD( X(i-1), Y(j-1) ) + p(i,j) , 297 // WLD( X(i) , Y(j-1) ) + q , 298 // WLD( X(i-1), Y(j) ) + r ) 299 npDistance[i] = Min3( d1 + nPij, d2 + nQ, npDistance[i-1] + nR ); 300 if ( npDistance[i] < nSPMin ) 301 nSPMin = npDistance[i]; 302 if ( bSplitCount ) 303 { 304 if ( nReplacePos < 0 && nPij && npDistance[i] == d1 + nPij ) 305 { // diese Stelle wird ersetzt 306 nRepS++; 307 nReplacePos = i; 308 #ifdef erTESTMAT 309 npMatrix[i][j+1] = -npDistance[i]; 310 #endif 311 } 312 else if ( nReplacePos > 0 && !nPij ) 313 { // Zeichen in String und Pattern gleich. 314 // wenn ab hier die gleiche Anzahl dieses Zeichens 315 // sowohl in Pattern als auch in String ist, und vor 316 // dieser Stelle das Zeichen gleich oft vorkommt, war das 317 // Replace keins. Buchstabendreher werden hier erfasst 318 // und der ReplaceS zurueckgenommen, wodurch das doppelte 319 // Limit zum Tragen kommt. 320 int nBalance = 0; // gleiche Anzahl c 321 LEVDISBALANCE( j, i-1 ); 322 if ( !nBalance ) 323 { // einer wurde ersetzt, der ein Insert war 324 nRepS--; 325 #ifdef erTESTMAT 326 npMatrix[nReplacePos][j+1] = npDistance[nReplacePos]; 327 #endif 328 nReplacePos = 0; 329 } 330 } 331 } 332 } 333 #ifdef erTESTMAT 334 { 335 for ( sal_Int32 r=0; r<=nStringLen && r < erTESTMATMAX; r++ ) 336 if ( npMatrix[r][j+1] >= 0) 337 npMatrix[r][j+1] = npDistance[r]; 338 } 339 #endif 340 } 341 #ifdef erTESTSPLIT 342 printf(" nRepS: %d ", nRepS ); 343 #endif 344 if ( (nSPMin <= nLimit) && (npDistance[nStringLen] <= nLimit) ) 345 return(npDistance[nStringLen]); 346 else 347 { 348 if ( bSplitCount ) 349 { 350 if ( nRepS && nLenDiff > 0 ) 351 nRepS -= nLenDiff; // Inserts wurden mitgezaehlt 352 #ifdef erTESTSPLIT 353 printf(" nRepSdiff: %d ", nRepS ); 354 #endif 355 if ( (nSPMin <= 2 * nLimit) 356 && (npDistance[nStringLen] <= 2 * nLimit) 357 && (nRepS * nRepP0 <= nLimit) ) 358 return( -npDistance[nStringLen] ); 359 return(LEVDISBIG); 360 } 361 return(LEVDISBIG); 362 } 363 } 364 365 366 367 // Berechnung von nLimit, nReplP0, nInsQ0, nDelR0, bSplitCount 368 // aus Userwerten nOtherX, nShorterY, nLongerZ, bRelaxed 369 int WLevDistance::CalcLPQR( int nX, int nY, int nZ, bool bRelaxed ) 370 { 371 int nMin, nMid, nMax; 372 if ( nX < 0 ) nX = 0; // nur positive Werte 373 if ( nY < 0 ) nY = 0; 374 if ( nZ < 0 ) nZ = 0; 375 if ( 0 == (nMin = Min3( nX, nY, nZ )) ) // mindestens einer 0 376 { 377 nMax = Max3( nX, nY, nZ ); // entweder 0 bei drei 0 oder Max 378 if ( 0 == (nMid = Mid3( nX, nY, nZ )) ) // sogar zwei 0 379 nLimit = nMax; // entweder 0 oder einziger >0 380 else // einer 0 381 nLimit = KGV( nMid, nMax ); 382 } 383 else // alle drei nicht 0 384 nLimit = KGV( KGV( nX, nY ), nZ ); 385 nRepP0 = ( nX ? nLimit / nX : nLimit + 1 ); 386 nInsQ0 = ( nY ? nLimit / nY : nLimit + 1 ); 387 nDelR0 = ( nZ ? nLimit / nZ : nLimit + 1 ); 388 bSplitCount = bRelaxed; 389 return( nLimit ); 390 } 391 392 393 394 // Groesster Gemeinsamer Teiler nach Euklid (Kettendivision) 395 // Sonderfall: 0 und irgendwas geben 1 396 int WLevDistance::GGT( int a, int b ) 397 { 398 if ( !a || !b ) 399 return 1; 400 if ( a < 0 ) a = -a; 401 if ( b < 0 ) b = -b; 402 do 403 { 404 if ( a > b ) 405 a -= int(a / b) * b; 406 else 407 b -= int(b / a) * a; 408 } while ( a && b ); 409 return( a ? a : b); 410 } 411 412 413 414 // Kleinstes Gemeinsames Vielfaches: a * b / GGT(a,b) 415 int WLevDistance::KGV( int a, int b ) 416 { 417 if ( a > b ) // Ueberlauf unwahrscheinlicher machen 418 return( (a / GGT(a,b)) * b ); 419 else 420 return( (b / GGT(a,b)) * a ); 421 } 422 423 424 // Minimum von drei Werten 425 inline int WLevDistance::Min3( int x, int y, int z ) 426 { 427 if ( x < y ) 428 return( x < z ? x : z ); 429 else 430 return( y < z ? y : z ); 431 } 432 433 434 435 // mittlerer von drei Werten 436 int WLevDistance::Mid3( int x, int y, int z ) 437 { 438 int min = Min3(x,y,z); 439 if ( x == min ) 440 return( y < z ? y : z); 441 else if ( y == min ) 442 return( x < z ? x : z); 443 else // z == min 444 return( x < y ? x : y); 445 } 446 447 448 449 // Maximum von drei Werten 450 int WLevDistance::Max3( int x, int y, int z ) 451 { 452 if ( x > y ) 453 return( x > z ? x : z ); 454 else 455 return( y > z ? y : z ); 456 } 457 458 459 460 // Daten aus CTor initialisieren 461 void WLevDistance::InitData( const sal_Unicode* cPattern ) 462 { 463 cpPattern = aPatMem.GetcPtr(); 464 bpPatIsWild = aPatMem.GetbPtr(); 465 npDistance = aDisMem.GetPtr(); 466 nStars = 0; 467 const sal_Unicode* cp1 = cPattern; 468 sal_Unicode* cp2 = cpPattern; 469 bool* bp = bpPatIsWild; 470 // Pattern kopieren, Sternchen zaehlen, escaped Jokers 471 while ( *cp1 ) 472 { 473 if ( *cp1 == '\\' ) // maybe escaped 474 { 475 if ( *(cp1+1) == '*' || *(cp1+1) == '?' ) // naechstes Joker? 476 { 477 cp1++; // skip '\\' 478 nPatternLen--; 479 } 480 *bp++ = false; 481 } 482 else if ( *cp1 == '*' || *cp1 == '?' ) // Joker 483 { 484 if ( *cp1 == '*' ) 485 nStars++; // Sternchenzaehler erhoehen 486 *bp++ = true; 487 } 488 else 489 *bp++ = false; 490 *cp2++ = *cp1++; 491 } 492 *cp2 = '\0'; 493 } 494 495 496 // CTor 497 498 #ifdef erTEST 499 500 WLevDistance::WLevDistance( const ::rtl::OUString& rPattern ) : 501 nPatternLen( rPattern.getLength() ), 502 aPatMem( nPatternLen + 1 ), 503 nArrayLen( nPatternLen + 1 ), 504 aDisMem( nArrayLen ), 505 nLimit( LEVDISDEFAULTLIMIT ), 506 nRepP0( LEVDISDEFAULT_P0 ), 507 nInsQ0( LEVDISDEFAULT_Q0 ), 508 nDelR0( LEVDISDEFAULT_R0 ), 509 bSplitCount( false ) 510 { 511 InitData( rPattern.getStr() ); 512 } 513 514 #endif // erTEST 515 516 517 WLevDistance::WLevDistance( const sal_Unicode* cPattern, 518 int nOtherX, int nShorterY, int nLongerZ, 519 bool bRelaxed ) : 520 nPatternLen( Impl_WLD_StringLen(cPattern) ), 521 aPatMem( nPatternLen + 1 ), 522 nArrayLen( nPatternLen + 1 ), 523 aDisMem( nArrayLen ) 524 { 525 InitData( cPattern ); 526 CalcLPQR( nOtherX, nShorterY, nLongerZ, bRelaxed ); 527 } 528 529 530 // CopyCTor 531 WLevDistance::WLevDistance( const WLevDistance& rWLD ) : 532 nPatternLen( rWLD.nPatternLen ), 533 aPatMem( nPatternLen + 1 ), 534 nArrayLen( nPatternLen + 1 ), 535 aDisMem( nArrayLen ), 536 nLimit( rWLD.nLimit ), 537 nRepP0( rWLD.nRepP0 ), 538 nInsQ0( rWLD.nInsQ0 ), 539 nDelR0( rWLD.nDelR0 ), 540 nStars( rWLD.nStars ), 541 bSplitCount( rWLD.bSplitCount ) 542 { 543 cpPattern = aPatMem.GetcPtr(); 544 bpPatIsWild = aPatMem.GetbPtr(); 545 npDistance = aDisMem.GetPtr(); 546 sal_Int32 i; 547 for ( i=0; i<nPatternLen; i++ ) 548 { 549 cpPattern[i] = rWLD.cpPattern[i]; 550 bpPatIsWild[i] = rWLD.bpPatIsWild[i]; 551 } 552 cpPattern[i] = '\0'; 553 } 554 555 556 // DTor 557 WLevDistance::~WLevDistance() 558 { 559 } 560 561 /************************************************************************* 562 * Test 563 *************************************************************************/ 564 565 #ifdef erTEST 566 567 #define LINESIZE 1000 568 typedef char MAXSTRING [LINESIZE+1]; 569 570 #ifdef erTESTMAT 571 572 void WLevDistance::ShowMatrix( const sal_Unicode* cString ) 573 { 574 sal_Int32 r, c, l = Impl_WLD_StringLen(cString); 575 printf(" | "); 576 for ( c=0; c<nPatternLen; c++ ) 577 #error Error: conversion from sal_Unicode to char needed! 578 printf( " %c ", cpPattern[c] ); 579 printf("\n---+---"); 580 for ( c=0; c<nPatternLen; c++ ) 581 printf( "---" ); 582 for ( r=0; r<=l && r < erTESTMATMAX; r++ ) 583 { 584 #error Error: conversion from sal_Unicode to char needed! 585 printf( "\n %c |", ( r==0 ? ' ' : cString[r-1] ) ); 586 for ( c=0; c<=nPatternLen && c < erTESTMATMAX; c++ ) 587 printf( "%2d ", npMatrix[r][c] ); 588 } 589 printf("\n\n"); 590 } 591 592 #endif // erTESTMAT 593 594 // Delimiter fuer Token, \t Tab bleibt fuer immer an der ersten Stelle 595 MAXSTRING cDelim = "\t, ;(){}[]<>&=+-/%!|.\\'\"~"; 596 597 void WLevDistance::ShowTest() 598 { 599 printf(" \n"); 600 #error Error: conversion from sal_Unicode to char needed! 601 printf(" a *cpPattern . . . . : %s\n", cpPattern); 602 printf(" b *bpPatIsWild . . . : "); 603 for ( sal_Int32 i=0; i<nPatternLen; i++ ) 604 printf("%d", bpPatIsWild[i]); 605 printf("\n"); 606 printf(" c nPatternLen . . . : %d\n", (int)nPatternLen); 607 printf(" d nStars . . . . . . : %d\n", nStars); 608 printf(" e nLimit . . . . . . : %d\n", nLimit); 609 printf(" f nRepP0 (Ersetzen) : %d\n", nRepP0); 610 printf(" g nInsQ0 (Einfuegen) : %d\n", nInsQ0); 611 printf(" h nDelR0 (Loeschen) : %d\n", nDelR0); 612 printf(" i bSplitCount . . . : %d\n", bSplitCount); 613 #error Error: conversion from sal_Unicode to char needed! 614 printf(" j cDelim . . . . . . : '%s'\n", cDelim); 615 printf(" ~\n"); 616 } 617 618 inline bool IsDelim( char c ) 619 { 620 char* cp = cDelim; 621 while ( *cp ) 622 if ( *cp++ == c ) 623 return( true ); 624 return( false ); 625 } 626 627 MAXSTRING cString, cLine, cIgString; 628 629 int main( int argc, char **argv ) 630 { 631 int nLim, nP0, nQ0, nR0, nX, nY, nZ; 632 int args = 0; 633 bool IgnoreCase = false, Direct = false, bStrict = false; 634 WLevDistance* pTest; 635 if ( argc < 2 ) 636 { 637 printf("%s Syntax:\n" 638 " ... [-i] cPattern [nOtherX, nShorterY, nLongerZ [bStrict [cDelim]]] [<stdin] [>stdout]\n" 639 " ... -d cPattern [nLimit [nRepP0 nInsQ0 nDelR0 [cDelim]]] [<stdin] [>stdout]\n" 640 , argv[0]); 641 exit(1); 642 } 643 if ( *argv[1] == '-' ) 644 { 645 args++; 646 argc--; 647 switch ( *(argv[1]+1) ) 648 { 649 case 'i': 650 { 651 IgnoreCase = true; 652 char* cp = argv[args+1]; 653 while ( (*cp = tolower( *cp )) != 0 ) 654 cp++; 655 break; 656 } 657 case 'd': 658 Direct = true; 659 break; 660 } 661 } 662 if ( Direct ) 663 { 664 if ( argc > 2 ) 665 nLim = atoi(argv[args+2]); 666 else 667 nLim = LEVDISDEFAULTLIMIT; 668 if ( argc > 3 ) 669 { 670 nP0 = atoi(argv[args+3]); 671 nQ0 = atoi(argv[args+4]); 672 nR0 = atoi(argv[args+5]); 673 } 674 else 675 { 676 nP0 = LEVDISDEFAULT_P0; 677 nQ0 = LEVDISDEFAULT_Q0; 678 nR0 = LEVDISDEFAULT_R0; 679 } 680 if ( argc > 6 ) 681 { 682 strncpy( cDelim+1, argv[args+6], LINESIZE ); // \t Tab always remains 683 cDelim[LINESIZE-1] = 0; 684 } 685 } 686 else 687 { 688 if ( argc > 2 ) 689 { 690 nX = atoi(argv[args+2]); 691 nY = atoi(argv[args+3]); 692 nZ = atoi(argv[args+4]); 693 } 694 else 695 { 696 nX = LEVDISDEFAULT_XOTHER; 697 nY = LEVDISDEFAULT_YSHORTER; 698 nZ = LEVDISDEFAULT_ZLONGER; 699 } 700 if ( argc > 5 ) 701 bStrict = atoi(argv[args+5]); 702 if ( argc > 6 ) 703 { 704 strncpy( cDelim+1, argv[args+6], LINESIZE ); // \t Tab always remains 705 cDelim[LINESIZE-1] = 0; 706 } 707 } 708 if ( Direct ) 709 { 710 #error Error: conversion from char to OUString needed! 711 pTest = new WLevDistance( argv[args+1] ); 712 #ifdef erTESTDEFAULT 713 pTest->ShowTest(); 714 #endif 715 pTest->SetLimit( nLim ); 716 pTest->SetReplaceP0( nP0 ); 717 pTest->SetInsertQ0( nQ0 ); 718 pTest->SetDeleteR0( nR0 ); 719 } 720 else 721 { 722 #error Error: conversion from char to sal_Unicode needed! 723 pTest = new WLevDistance( argv[args+1], nX, nY, nZ, !bStrict ); 724 #ifdef erTESTCCTOR 725 WLevDistance aTmp( *pTest ); 726 aTmp.ShowTest(); 727 #endif 728 nLim = pTest->GetLimit(); 729 } 730 pTest->ShowTest(); 731 do 732 { 733 char* cp1, *cp2; 734 static long unsigned int nLine = 0; 735 cp1 = cLine; 736 cin.getline( cLine, LINESIZE ) ; 737 nLine++; 738 while ( *cp1 ) 739 { 740 while ( *cp1 && IsDelim(*cp1) ) 741 cp1++; 742 cp2 = cString; 743 while ( *cp1 && !IsDelim(*cp1) ) 744 *cp2++ = *cp1++; 745 *cp2 = '\0'; 746 while ( *cp1 && IsDelim(*cp1) ) 747 cp1++; 748 if ( *cString ) 749 { 750 int ret; 751 if ( IgnoreCase ) 752 { 753 char* cpi1 = cString; 754 char* cpi2 = cIgString; 755 while ( *cpi1 ) 756 *cpi2++ = tolower( *cpi1++ ); 757 *cpi2 = '\0'; 758 #error Error: conversion from char to OUString / sal_Unicode,length needed! 759 ret = pTest->WLD( cIgString ); 760 } 761 else 762 #error Error: conversion from char to OUString / sal_Unicode,length needed! 763 ret = pTest->WLD( cString ); 764 #ifdef erTESTMAT 765 printf("\n# %3d : %s\n", ret, cString); 766 #error Error: conversion from char to sal_Unicode needed! 767 pTest->ShowMatrix( cString ); 768 #else 769 if ( ret <= nLim ) 770 printf("# %3d : %s\t(line %lu)\t%s\n", ret, cString, nLine, cLine); 771 #endif 772 } 773 } 774 } while ( !cin.eof() ); 775 return 0; 776 } 777 778 #endif // erTEST 779 780