From 5a9526bcf3fbaf00a392522847446e39d3790d7d Mon Sep 17 00:00:00 2001 From: vvatanabe Date: Wed, 9 Aug 2023 06:52:40 +0900 Subject: [PATCH 1/2] style: format code and optimize imports in matchers.RepeatMatcher --- .../zxcvbn/matchers/RepeatMatcher.java | 88 +++++++++++-------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/nulabinc/zxcvbn/matchers/RepeatMatcher.java b/src/main/java/com/nulabinc/zxcvbn/matchers/RepeatMatcher.java index 505d3e1..78a9ca9 100644 --- a/src/main/java/com/nulabinc/zxcvbn/matchers/RepeatMatcher.java +++ b/src/main/java/com/nulabinc/zxcvbn/matchers/RepeatMatcher.java @@ -5,51 +5,61 @@ import com.nulabinc.zxcvbn.Scoring; import com.nulabinc.zxcvbn.Strength; import com.nulabinc.zxcvbn.WipeableString; - import java.util.ArrayList; import java.util.List; import java.util.regex.*; public class RepeatMatcher extends BaseMatcher { - public RepeatMatcher(final Context context) { - super(context); - } + public RepeatMatcher(final Context context) { + super(context); + } - @Override - public List execute(CharSequence password) { - List matches = new ArrayList<>(); - Pattern greedy = Pattern.compile("(.+)\\1+"); - Pattern lazy = Pattern.compile("(.+?)\\1+"); - Pattern lazyAnchored = Pattern.compile("^(.+?)\\1+$"); - int passwordLength = password.length(); - int lastIndex = 0; - Scoring scoring = new Scoring(this.getContext()); - while(lastIndex < passwordLength) { - java.util.regex.Matcher greedyMatch = greedy.matcher(password); - java.util.regex.Matcher lazyMatch = lazy.matcher(password); - greedyMatch.region(lastIndex, passwordLength); - lazyMatch.region(lastIndex, passwordLength); - if (!greedyMatch.find()) break; - java.util.regex.Matcher match; - CharSequence baseToken; - if(greedyMatch.group(0).length() > (lazyMatch.find() ? lazyMatch.group(0).length() : 0)) { - match = greedyMatch; - Matcher matcher = lazyAnchored.matcher(match.group(0)); - baseToken = matcher.find() ? matcher.group(1) : match.group(0); - } else { - match = lazyMatch; - baseToken = match.group(1); - } - int i = match.start(0); - int j = match.start(0) + match.group(0).length() - 1; - Strength baseAnalysis = scoring.mostGuessableMatchSequence(baseToken, new Matching(this.getContext(), new ArrayList()).omnimatch(baseToken)); - List baseMatches = baseAnalysis.getSequence(); - double baseGuesses = baseAnalysis.getGuesses(); - baseToken = new WipeableString(baseToken); - matches.add(MatchFactory.createRepeatMatch(i, j, match.group(0), baseToken, baseGuesses, baseMatches, match.group(0).length() / baseToken.length())); - lastIndex = j + 1; - } - return matches; + @Override + public List execute(CharSequence password) { + List matches = new ArrayList<>(); + Pattern greedy = Pattern.compile("(.+)\\1+"); + Pattern lazy = Pattern.compile("(.+?)\\1+"); + Pattern lazyAnchored = Pattern.compile("^(.+?)\\1+$"); + int passwordLength = password.length(); + int lastIndex = 0; + Scoring scoring = new Scoring(this.getContext()); + while (lastIndex < passwordLength) { + java.util.regex.Matcher greedyMatch = greedy.matcher(password); + java.util.regex.Matcher lazyMatch = lazy.matcher(password); + greedyMatch.region(lastIndex, passwordLength); + lazyMatch.region(lastIndex, passwordLength); + if (!greedyMatch.find()) break; + java.util.regex.Matcher match; + CharSequence baseToken; + if (greedyMatch.group(0).length() > (lazyMatch.find() ? lazyMatch.group(0).length() : 0)) { + match = greedyMatch; + Matcher matcher = lazyAnchored.matcher(match.group(0)); + baseToken = matcher.find() ? matcher.group(1) : match.group(0); + } else { + match = lazyMatch; + baseToken = match.group(1); + } + int i = match.start(0); + int j = match.start(0) + match.group(0).length() - 1; + Strength baseAnalysis = + scoring.mostGuessableMatchSequence( + baseToken, + new Matching(this.getContext(), new ArrayList()).omnimatch(baseToken)); + List baseMatches = baseAnalysis.getSequence(); + double baseGuesses = baseAnalysis.getGuesses(); + baseToken = new WipeableString(baseToken); + matches.add( + MatchFactory.createRepeatMatch( + i, + j, + match.group(0), + baseToken, + baseGuesses, + baseMatches, + match.group(0).length() / baseToken.length())); + lastIndex = j + 1; } + return matches; + } } From 6d9b45976493af94166aca029c4e49a6a0c0a132 Mon Sep 17 00:00:00 2001 From: vvatanabe Date: Wed, 9 Aug 2023 06:54:42 +0900 Subject: [PATCH 2/2] refactor: refactoring matchers.RepeatMatcher --- .../zxcvbn/matchers/RepeatMatcher.java | 153 ++++++++++++------ 1 file changed, 102 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/nulabinc/zxcvbn/matchers/RepeatMatcher.java b/src/main/java/com/nulabinc/zxcvbn/matchers/RepeatMatcher.java index 78a9ca9..fd7005a 100644 --- a/src/main/java/com/nulabinc/zxcvbn/matchers/RepeatMatcher.java +++ b/src/main/java/com/nulabinc/zxcvbn/matchers/RepeatMatcher.java @@ -7,59 +7,110 @@ import com.nulabinc.zxcvbn.WipeableString; import java.util.ArrayList; import java.util.List; -import java.util.regex.*; +import java.util.regex.Pattern; public class RepeatMatcher extends BaseMatcher { - public RepeatMatcher(final Context context) { - super(context); - } - - @Override - public List execute(CharSequence password) { - List matches = new ArrayList<>(); - Pattern greedy = Pattern.compile("(.+)\\1+"); - Pattern lazy = Pattern.compile("(.+?)\\1+"); - Pattern lazyAnchored = Pattern.compile("^(.+?)\\1+$"); - int passwordLength = password.length(); - int lastIndex = 0; - Scoring scoring = new Scoring(this.getContext()); - while (lastIndex < passwordLength) { - java.util.regex.Matcher greedyMatch = greedy.matcher(password); - java.util.regex.Matcher lazyMatch = lazy.matcher(password); - greedyMatch.region(lastIndex, passwordLength); - lazyMatch.region(lastIndex, passwordLength); - if (!greedyMatch.find()) break; - java.util.regex.Matcher match; - CharSequence baseToken; - if (greedyMatch.group(0).length() > (lazyMatch.find() ? lazyMatch.group(0).length() : 0)) { - match = greedyMatch; - Matcher matcher = lazyAnchored.matcher(match.group(0)); - baseToken = matcher.find() ? matcher.group(1) : match.group(0); - } else { - match = lazyMatch; - baseToken = match.group(1); - } - int i = match.start(0); - int j = match.start(0) + match.group(0).length() - 1; - Strength baseAnalysis = - scoring.mostGuessableMatchSequence( - baseToken, - new Matching(this.getContext(), new ArrayList()).omnimatch(baseToken)); - List baseMatches = baseAnalysis.getSequence(); - double baseGuesses = baseAnalysis.getGuesses(); - baseToken = new WipeableString(baseToken); - matches.add( - MatchFactory.createRepeatMatch( - i, - j, - match.group(0), - baseToken, - baseGuesses, - baseMatches, - match.group(0).length() / baseToken.length())); - lastIndex = j + 1; + private static final Pattern GREEDY_PATTERN = Pattern.compile("(.+)\\1+"); + private static final Pattern LAZY_PATTERN = Pattern.compile("(.+?)\\1+"); + private static final Pattern LAZY_ANCHORED_PATTERN = Pattern.compile("^(.+?)\\1+$"); + + private final Scoring scoring; + private final Matching matching; + + public RepeatMatcher(final Context context) { + super(context); + this.scoring = new Scoring(context); + this.matching = new Matching(context, new ArrayList()); + } + + @Override + public List execute(CharSequence password) { + List matches = new ArrayList<>(); + int passwordLength = password.length(); + int lastIndex = 0; + + while (lastIndex < passwordLength) { + java.util.regex.Matcher greedyMatcher = + createRegionMatcher(GREEDY_PATTERN, password, lastIndex, passwordLength); + java.util.regex.Matcher lazyMatcher = + createRegionMatcher(LAZY_PATTERN, password, lastIndex, passwordLength); + + if (!greedyMatcher.find()) { + break; + } + + ChosenMatch chosenMatch = chooseMatch(greedyMatcher, lazyMatcher); + Match repeatMatch = + createRepeatMatch( + chosenMatch.baseToken, chosenMatch.matchResult, chosenMatch.start, chosenMatch.end); + matches.add(repeatMatch); + lastIndex = chosenMatch.end + 1; + } + + return matches; + } + + private java.util.regex.Matcher createRegionMatcher( + Pattern pattern, CharSequence password, int start, int end) { + java.util.regex.Matcher matcher = pattern.matcher(password); + matcher.region(start, end); + return matcher; + } + + private ChosenMatch chooseMatch( + java.util.regex.Matcher greedyMatcher, java.util.regex.Matcher lazyMatcher) { + + String greedyMatchResult = greedyMatcher.group(0); + String lazyMatchResult = lazyMatcher.find() ? lazyMatcher.group(0) : ""; + boolean isGreedyLonger = greedyMatchResult.length() > lazyMatchResult.length(); + + String matchResult; + CharSequence baseToken; + int start; + int end; + + if (isGreedyLonger) { + matchResult = greedyMatchResult; + baseToken = deriveBaseTokenFromGreedyMatchResult(greedyMatchResult); + start = greedyMatcher.start(0); + end = start + greedyMatchResult.length() - 1; + } else { + matchResult = lazyMatchResult; + baseToken = lazyMatcher.group(1); + start = lazyMatcher.start(0); + end = start + lazyMatchResult.length() - 1; + } + return new ChosenMatch(matchResult, baseToken, start, end); + } + + private CharSequence deriveBaseTokenFromGreedyMatchResult(String greedyMatchResult) { + java.util.regex.Matcher lazyAnchoredMatcher = LAZY_ANCHORED_PATTERN.matcher(greedyMatchResult); + return lazyAnchoredMatcher.find() ? lazyAnchoredMatcher.group(1) : greedyMatchResult; + } + + private Match createRepeatMatch(CharSequence baseToken, String matchResult, int start, int end) { + List omnimatch = matching.omnimatch(baseToken); + Strength baseAnalysis = scoring.mostGuessableMatchSequence(baseToken, omnimatch); + List baseMatches = baseAnalysis.getSequence(); + double baseGuesses = baseAnalysis.getGuesses(); + CharSequence wipeableBaseToken = new WipeableString(baseToken); + int repeatCount = matchResult.length() / wipeableBaseToken.length(); + return MatchFactory.createRepeatMatch( + start, end, matchResult, wipeableBaseToken, baseGuesses, baseMatches, repeatCount); + } + + private static class ChosenMatch { + final String matchResult; + final CharSequence baseToken; + final int start; + final int end; + + public ChosenMatch(String matchResult, CharSequence baseToken, int start, int end) { + this.matchResult = matchResult; + this.baseToken = baseToken; + this.start = start; + this.end = end; + } } - return matches; - } }