// Distance from string to pattern int WLevDistance::WLD( const sal_Unicode* cString, sal_Int32 nStringLen )
{ int nSPMin = 0; // penalty point Minimum int nRepS = 0; // for SplitCount
// length difference between pattern and string int nLenDiff = nPatternLen - nStars - nStringLen; // more insertions or deletions necessary as the limit? Then leave if ( (nLenDiff * nInsQ0 > nLimit)
|| ((nStars == 0) && (nLenDiff * nDelR0 < -nLimit)) ) return LEVDISBIG;
// comparative String greater than instantaneous array // -> adapt array size if ( nStringLen >= nArrayLen )
{ // increase size much more to avoid reallocation if ( nStringLen < LEVDISDOUBLEBUF )
nArrayLen = 2 * nStringLen; else
nArrayLen = nStringLen + 1;
npDistance = aDisMem.NewMem( nArrayLen );
}
// Calculate start values of the second column (first pattern value). // First column (0-Len pattern) is always zero .. nStringLen * nInsQ0, // therefore the minimum is 0 if ( nPatternLen == 0 )
{ // Count of deletions to reach pattern for ( sal_Int32 i=0; i <= nStringLen; i++ )
npDistance[i] = i * nDelR0;
} elseif ( cpPattern[0] == '*' && bpPatIsWild[0] )
{ // instead of a '*' you can fit in anything for ( sal_Int32 i=0; i <= nStringLen; i++ )
npDistance[i] = 0;
} else
{
sal_Unicode c; int nP;
c = cpPattern[0]; if ( c == '?' && bpPatIsWild[0] )
nP = 0; // a '?' could be any character. else // Minimum of replacement and deletion+insertion weighting
nP = std::min({ nRepP0, nRepP0, nDelR0 + nInsQ0 });
npDistance[0] = nInsQ0; // start with simple insert
npDistance[1] = nInsQ0;
npDistance[2] = nInsQ0; int nReplacePos = -1; // tristate flag int nDelCnt = 0; for ( sal_Int32 i=1; i <= nStringLen; i++, nDelCnt += nDelR0 )
{ if ( cString[i-1] == c )
nP = 0; // Replace from this position is 0 // Deletions to match pattern + Replace
npDistance[i] = nDelCnt + nP; if ( bSplitCount )
{ if ( nReplacePos < 0 && nP )
{ // this position will be replaced
nRepS++;
nReplacePos = i;
} elseif ( nReplacePos > 0 && !nP )
{ // same count of c int nBalance = levdisbalance( 0, i-1, c, cString, nStringLen ); if ( !nBalance )
{ // one was replaced that was an insertion instead
nRepS--;
nReplacePos = 0;
}
}
}
}
nSPMin = std::min({ npDistance[0], npDistance[1], npDistance[2] });
}
// calculate distance matrix
sal_Int32 j = 0; // for all columns of the pattern, till limit is not reached while ( (j < nPatternLen-1)
&& nSPMin <= (bSplitCount ? 2 * nLimit : nLimit) )
{
sal_Unicode c; int nP, nQ, nR, nPij, d2;
j++;
c = cpPattern[j]; if ( bpPatIsWild[j] ) // '*' or '?' not escaped
nP = 0; // could be replaced without penalty else
nP = nRepP0; if ( c == '*' && bpPatIsWild[j] )
{
nQ = 0; // insertion and deletion without penalty
nR = 0;
} else
{
nQ = nInsQ0; // usual weighting
nR = nDelR0;
}
d2 = npDistance[0]; // increase insert count to get from null string to pattern
npDistance[0] = npDistance[0] + nQ;
nSPMin = npDistance[0]; int nReplacePos = -1; // tristate flag // for each pattern column run through the string for ( sal_Int32 i=1; i <= nStringLen; i++ )
{ int d1 = d2; // WLD( X(i-1), Y(j-1) )
d2 = npDistance[i]; // WLD( X(i) , Y(j-1) ) if ( cString[i-1] == c )
{
nPij = 0; // p(i,j) if ( nReplacePos < 0 )
{ // same count of c int nBalance = levdisbalance( j, i-1, c, cString, nStringLen ); if ( !nBalance )
nReplacePos = 0; // no replacement
}
} else
nPij = nP; // WLD( X(i), Y(j) ) = min( WLD( X(i-1), Y(j-1) ) + p(i,j) , // WLD( X(i) , Y(j-1) ) + q , // WLD( X(i-1), Y(j) ) + r )
npDistance[i] = std::min({ d1 + nPij, d2 + nQ, npDistance[i-1] + nR }); if ( npDistance[i] < nSPMin )
nSPMin = npDistance[i]; if ( bSplitCount )
{ if ( nReplacePos < 0 && nPij && npDistance[i] == d1 + nPij )
{ // this position will be replaced
nRepS++;
nReplacePos = i;
} elseif ( nReplacePos > 0 && !nPij )
{ // character is equal in string and pattern // // If from this point: // * pattern and string have the same count of this // character // * and character count is the same before this position // then the replace was none. // // Scrambled letters are recognized here and the nRepS // replacement is withdrawn, whereby the double limit kicks // in.
// Same count of c int nBalance = levdisbalance( j, i-1, c, cString, nStringLen ); if ( !nBalance )
{ // one was replaced that was an insertion instead
nRepS--;
nReplacePos = 0;
}
}
}
}
} if ( (nSPMin <= nLimit) && (npDistance[nStringLen] <= nLimit) ) return npDistance[nStringLen]; else
{ if ( bSplitCount )
{ if ( nRepS && nLenDiff > 0 )
nRepS -= nLenDiff; // Inserts were counted if ( (nSPMin <= 2 * nLimit)
&& (npDistance[nStringLen] <= 2 * nLimit)
&& (nRepS * nRepP0 <= nLimit) ) return -npDistance[nStringLen]; return LEVDISBIG;
} return LEVDISBIG;
}
}
// Calculating nLimit, nReplP0, nInsQ0, nDelR0, bSplitCount // from user values nOtherX, nShorterY, nLongerZ, bRelaxed void WLevDistance::CalcLPQR( int nX, int nY, int nZ, bool bRelaxed )
{ if ( nX < 0 ) nX = 0; // only positive values if ( nY < 0 ) nY = 0; if ( nZ < 0 ) nZ = 0; if (0 == std::min({ nX, nY, nZ })) // at least one 0
{ int nMid, nMax;
nMax = std::max({ nX, nY, nZ }); // either 0 for three 0s or Max if ( 0 == (nMid = Mid3( nX, nY, nZ )) ) // even two 0
nLimit = nMax; // either 0 or the only one >0 else// one is 0
nLimit = std::lcm( nMid, nMax );
} else// all three of them are not 0
nLimit = std::lcm(std::lcm(nX, nY), nZ);
nRepP0 = ( nX ? nLimit / nX : nLimit + 1 );
nInsQ0 = ( nY ? nLimit / nY : nLimit + 1 );
nDelR0 = ( nZ ? nLimit / nZ : nLimit + 1 );
bSplitCount = bRelaxed;
}
// The value in the middle int WLevDistance::Mid3( int x, int y, int z )
{ int min = std::min({ x, y, z }); if ( x == min ) return std::min(y, z); elseif ( y == min ) return std::min(x, z); else// z == min return std::min(x, y);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.