Files
SnowLuma/.pnpm-store/v11/files/d1/36c5837c189484afa50b70bb53f568a2932cc90bb618a440e88f4fe1dc9b64813ae3f65a919cb1fd91f3bd07bb3ba1862e2e99199f81e97613f969e25d01f0
T
TanTan 2a69b23b47
Dev Build / cleanup (push) Waiting to run
Dev Build / typecheck (push) Waiting to run
docs: 仓库链接指向本镜像仓库
2026-11-13 09:27:07 +08:00

129 lines
3.6 KiB
Plaintext

'use strict';
var types = require('../../types.cjs');
var index = require('../../scoring/index.cjs');
/*
*-------------------------------------------------------------------------------
* repeats (aaa, abcabcabc) ------------------------------
*-------------------------------------------------------------------------------
*/
class MatchRepeat extends types.MatcherBaseClass {
constructor(options) {
super(options);
this.scoring = new index(options);
}
// eslint-disable-next-line max-statements
match({
password,
omniMatch
}) {
const matches = [];
let lastIndex = 0;
while (lastIndex < password.length) {
const greedyMatch = this.getGreedyMatch(password, lastIndex);
const lazyMatch = this.getLazyMatch(password, lastIndex);
if (greedyMatch == null) {
break;
}
const {
match,
baseToken
} = this.setMatchToken(greedyMatch, lazyMatch);
if (match) {
const j = match.index + match[0].length - 1;
const baseGuesses = this.getBaseGuesses(baseToken, omniMatch);
matches.push(this.normalizeMatch(baseToken, j, match, baseGuesses));
lastIndex = j + 1;
}
}
const hasPromises = matches.some(match => {
return match instanceof Promise;
});
if (hasPromises) {
// eslint-disable-next-line @typescript-eslint/await-thenable
return Promise.all(matches);
}
return matches;
}
// eslint-disable-next-line max-params
normalizeMatch(baseToken, j, match, baseGuesses) {
const baseMatch = {
pattern: 'repeat',
i: match.index,
j,
token: match[0],
baseToken,
baseGuesses: 0,
repeatCount: match[0].length / baseToken.length
};
if (baseGuesses instanceof Promise) {
return baseGuesses.then(resolvedBaseGuesses => {
return {
...baseMatch,
baseGuesses: resolvedBaseGuesses
};
});
}
return {
...baseMatch,
baseGuesses
};
}
getGreedyMatch(password, lastIndex) {
const greedy = /(.+)\1+/g;
greedy.lastIndex = lastIndex;
return greedy.exec(password);
}
getLazyMatch(password, lastIndex) {
const lazy = /(.+?)\1+/g;
lazy.lastIndex = lastIndex;
return lazy.exec(password);
}
setMatchToken(greedyMatch, lazyMatch) {
const lazyAnchored = /^(.+?)\1+$/;
let match;
let baseToken = '';
if (lazyMatch && greedyMatch[0].length > lazyMatch[0].length) {
// greedy beats lazy for 'aabaab'
// greedy: [aabaab, aab]
// lazy: [aa, a]
match = greedyMatch;
// greedy's repeated string might itself be repeated, eg.
// aabaab in aabaabaabaab.
// run an anchored lazy match on greedy's repeated string
// to find the shortest repeated string
const temp = lazyAnchored.exec(match[0]);
if (temp) {
baseToken = temp[1];
}
} else {
// lazy beats greedy for 'aaaaa'
// greedy: [aaaa, aa]
// lazy: [aaaaa, a]
match = lazyMatch;
if (match) {
baseToken = match[1];
}
}
return {
match,
baseToken
};
}
getBaseGuesses(baseToken, omniMatch) {
const matches = omniMatch.match(baseToken);
if (matches instanceof Promise) {
return matches.then(resolvedMatches => {
const baseAnalysis = this.scoring.mostGuessableMatchSequence(baseToken, resolvedMatches);
return baseAnalysis.guesses;
});
}
const baseAnalysis = this.scoring.mostGuessableMatchSequence(baseToken, matches);
return baseAnalysis.guesses;
}
}
module.exports = MatchRepeat;
//# sourceMappingURL=matching.cjs.map