RegexPrefixCapturingPatternParser.java
- package org.jbehave.core.parsers;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
- import org.apache.commons.lang3.builder.ToStringBuilder;
- import org.apache.commons.lang3.builder.ToStringStyle;
- import org.jbehave.core.steps.StepType;
- /**
- * <p>A step pattern parser that provides a step matcher which will capture
- * parameters starting with the given prefix in any matching step. Default
- * prefix is $.</p>
- *
- * <p>The parameter names are by default assumed to be any unicode-supported
- * alphanumeric sequence, not limited to ASCII (see
- * http://www.regular-expressions.info/unicode.html), i.e. corresponding to
- * character class [\p{L}\p{N}\p{Pc}]. A different character class can optionally be
- * provided.</p>
- *
- * @author Elizabeth Keogh
- * @author Mauro Talevi
- */
- public class RegexPrefixCapturingPatternParser implements StepPatternParser {
- /**
- * The default prefix to identify parameter names
- */
- private static final String DEFAULT_PREFIX = "$";
- /**
- * The default character class to match the parameter names.
- */
- private static final String DEFAULT_CHARACTER_CLASS = "[\\p{L}\\p{N}\\p{Pc}]";
- private final String prefix;
- private final String characterClass;
- /**
- * Creates a parser which captures parameters starting with $ in a matching
- * step and whose names are alphanumeric sequences.
- */
- public RegexPrefixCapturingPatternParser() {
- this(DEFAULT_PREFIX);
- }
- /**
- * Creates a parser which captures parameters starting with a given prefix
- * in a matching step and whose names are alphanumeric sequences
- *
- * @param prefix
- * the prefix to use in capturing parameters
- */
- public RegexPrefixCapturingPatternParser(String prefix) {
- this(prefix, DEFAULT_CHARACTER_CLASS);
- }
- /**
- * Creates a parser which captures parameters starting with a given prefix
- * in a matching step and a given character class.
- *
- * @param prefix
- * the prefix to use in capturing parameters
- * @param characterClass
- * the regex character class to find parameter names
- */
- public RegexPrefixCapturingPatternParser(String prefix,
- String characterClass) {
- this.prefix = prefix;
- this.characterClass = characterClass;
- }
- public String getPrefix() {
- return prefix;
- }
- @Override
- public StepMatcher parseStep(StepType stepType, String stepPattern) {
- String escapingPunctuation = escapingPunctuation(stepPattern);
- List<Parameter> parameters = findParameters(escapingPunctuation);
- Pattern regexPattern = buildPattern(escapingPunctuation, parameters);
- return new RegexStepMatcher(stepType, escapingPunctuation, regexPattern,
- parameterNames(parameters));
- }
- private Pattern buildPattern(String stepPattern, List<Parameter> parameters) {
- return Pattern.compile(
- parameterCapturingRegex(stepPattern, parameters),
- Pattern.DOTALL);
- }
- private String[] parameterNames(List<Parameter> parameters) {
- List<String> names = new ArrayList<>();
- for (Parameter parameter : parameters) {
- names.add(parameter.name);
- }
- return names.toArray(new String[names.size()]);
- }
- private List<Parameter> findParameters(String pattern) {
- List<Parameter> parameters = new ArrayList<>();
- Matcher findingAllParameterNames = findingAllParameterNames().matcher(
- pattern);
- while (findingAllParameterNames.find()) {
- parameters.add(new Parameter(pattern, findingAllParameterNames
- .start(), findingAllParameterNames.end(),
- findingAllParameterNames.group(2)));
- }
- return parameters;
- }
- private Pattern findingAllParameterNames() {
- return Pattern.compile("(\\" + prefix + characterClass + "*)(\\W|\\Z)",
- Pattern.DOTALL);
- }
- private String escapingPunctuation(String pattern) {
- return pattern.replaceAll("([\\[\\]\\{\\}\\?\\^\\.\\*\\(\\)\\+\\\\])",
- "\\\\$1");
- }
- private String ignoringWhitespace(String pattern) {
- return pattern.replaceAll("\\s+", "\\\\s+");
- }
- private String parameterCapturingRegex(String stepPattern,
- List<Parameter> parameters) {
- String regex = stepPattern;
- String capture = "(.*)";
- for (int i = parameters.size(); i > 0; i--) {
- Parameter parameter = parameters.get(i - 1);
- String start = regex.substring(0, parameter.start);
- String end = regex.substring(parameter.end);
- String whitespaceIfAny = parameter.whitespaceIfAny;
- regex = start + capture + whitespaceIfAny + end;
- }
- return ignoringWhitespace(regex);
- }
- private class Parameter {
- private final int start;
- private final int end;
- private final String whitespaceIfAny;
- private final String name;
- public Parameter(String pattern, int start, int end,
- String whitespaceIfAny) {
- this.start = start;
- this.end = end;
- this.whitespaceIfAny = whitespaceIfAny;
- this.name = pattern.substring(start + prefix.length(),
- end - whitespaceIfAny.length()).trim();
- }
- @Override
- public String toString() {
- return name;
- }
- }
- @Override
- public String toString() {
- return ToStringBuilder.reflectionToString(this,
- ToStringStyle.SHORT_PREFIX_STYLE);
- }
- }