sirhc
sirhc

Reputation: 23

2 Java Regexes to validate google DFP entry

I am looking for 2 Regex validations for 2 input fields.

Background

I have a form (magnolia cms form) with 2 inputs that lets a user to enter Ad Sizes and Image Sizes for Google DFP. This is a magnolia cms form, where its value being validated in the backend (Java). If the entry pass the validation, it will be shown in the frontend. The validation here prevents user to enter wrong entry format which can cause Javascript error.

What I am trying to achieve here is validate these inputs with 2 Regex validations. One is for Ad Sizes input field, and the other one is for Image Sizes input field. The user is required to type everything manually, including square brackets and some integer values in it (see examples below).

In this question, an entry means a json-like array of 2 integers. E.g. [1, 10], [41,123], [0,0], etc..

The format and samples for the entries:

Ad sizes

If the user wants to enter 1 entry only (see example 1 and 2), then 1 array of 2 integers is sufficient. But if the user wants to enter more than 1 entry (example 3 and 4), then the user must encapsulate whole entries in 1 square brackets.

These entries should pass Ad sizes regex validation:

  1. [728, 90]
  2. [1,1]
  3. [[468, 60], [728, 90], [300, 250]]
  4. [[468, 60], [728, 90], [300, 250], [1, 1]]

These entries should NOT pass Ad sizes regex validation

  1. [212]
  2. [abcd]
  3. [1232,23111],[2312,323]
  4. [[2211,33],[22,321],[21]]
  5. 123,643

Image Sizes

For Image sizes, it should contain 2 main entries: the 1st one and the 2nd one. Both entries are separated by comma.

The first entry should be a 2 integer array. The 2nd entry can be:

These entries should pass Image sizes regex validation:

  1. [990, 300], [728, 90]
  2. [990, 300], [[728, 90], [320, 200], [80, 31], []]
  3. [990,300],[]
  4. [1, 1], []

These entries should NOT pass Image sizes regex validation:

  1. [123, 421]
  2. [123, 321, 531], [321, 33]
  3. 13,324,223,431
  4. [990], [728, 90]
  5. [990,300],[qwewqe,ggfggrg]

Thanks for the help.

Upvotes: 0

Views: 169

Answers (1)

Bradley Andersen
Bradley Andersen

Reputation: 311

There's a couple of ways to do this in Magnolia. I'll show both through an example.

First, we need a Component and a Dialog:

# component
dialog: valid:texttext
description: some yummy text you should enter
renderType: freemarker
title: Texttext
templateScript: /valid/templates/components/texttext.ftl

# dialog    
actions:
  commit:
    label: save changes
    class: info.magnolia.ui.admincentral.dialog.action.SaveDialogActionDefinition
  cancel:
    label: cancel
    class: info.magnolia.ui.admincentral.dialog.action.CancelDialogActionDefinition
form:
  tabs:
    - name: tabMain
      label: Texttext Dialog
      fields:
        - name: text1
          label: text1
          description: enter some text 1
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          validators:
            adsizes:
              class: info.magnolia.test.field.validator.SizeFieldsValidatorDefinition
              errorMessage: Invalid ad size entered
        - name: text2
          label: text2
          description: enter some text 2
          class: info.magnolia.ui.form.field.definition.TextFieldDefinition
          validators:
            imgsizes:
              class: info.magnolia.ui.form.validator.definition.RegexpValidatorDefinition
              errorMessage: invalid image size entered
              pattern: ^\[.*$

You'll notice I added two field validators: 'adsizes' and 'imgsizes'. The first way to do something like this is just with a big regex as a 'pattern' property to a RegexpValidatorDefinition, as I've done on the 'imgsizes' one. That particular regex could be anything ... the one I have up there just says we want the line to begin with a '[' character. In your particular example, you'd need a conditional regex to handle this in one line. A naive solution like

^\[(\[?\d+\,\s?\d+\]?\,?\s?){1,}\]$

Fails test #7 in Ad sizes, in your list.

In my opinion and experience, regexen are easier to debug / maintain if we don't try to be too smart with them. That is, instead of trying to do five things in one line, why not do five thing in five lines? That's where my second way comes in.

You'll notice on the text1 field I've attached a custom validator called SizeFieldsValidatorDefinition. This is the typical Magnolia pattern:

package info.magnolia.test.field.validator;

import info.magnolia.ui.form.validator.definition.ConfiguredFieldValidatorDefinition;

public class SizeFieldsValidatorDefinition extends ConfiguredFieldValidatorDefinition {
    public SizeFieldsValidatorDefinition() {
        setFactoryClass(SizeFieldsValidatorFactory.class);
    }
}


package info.magnolia.test.field.validator;

import info.magnolia.context.Context;
import info.magnolia.ui.form.validator.factory.AbstractFieldValidatorFactory;

import com.vaadin.data.Item;
import com.vaadin.data.Validator;

public class SizeFieldsValidatorFactory extends AbstractFieldValidatorFactory<SizeFieldsValidatorDefinition> {
    private final Item item;
    private final Context context;

    public SizeFieldsValidatorFactory(final SizeFieldsValidatorDefinition definition, final Item item, final Context context) {
        super(definition);

        this.item = item;
        this.context = context;
    }

    public Validator createValidator() {
        return new SizeFieldsValidator(item, context, getI18nErrorMessage());
    }
}


package info.magnolia.test.field.validator;

import info.magnolia.context.Context;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.lang3.StringUtils;

import com.vaadin.data.Item;
import com.vaadin.data.validator.AbstractStringValidator;

public class SizeFieldsValidator extends AbstractStringValidator {

    private final Item item;
    private final Context context;

    public SizeFieldsValidator(final Item item, final Context context, final String errorMessage) {
        super(errorMessage);

        this.item = item;
        this.context = context;
    }

    @Override
    protected boolean isValidValue(String text1) {
        if (!StringUtils.isEmpty(text1)) {
            return checkit(text1);
        }

        return false;
    }

    private boolean checkit(String text1) {
        // the atomic pattern '[number,number]':
        Pattern atom = Pattern.compile("\\[\\d+\\s?\\,\\s?\\d+\\]");

        // must start with '[' and end with ']' in all cases:
        Pattern pattern = Pattern.compile("^\\[(.*)\\]$");
        Matcher matcher = pattern.matcher(text1);
        if (!matcher.matches()) {
            return false;
        }

        // the bit inside the required outer '[' and ']':
        String data = matcher.group(1);

        // now check that the bits inside follow the plan:
        if (!Pattern.matches("\\d+\\s?\\,\\s?\\d+", data) && !Pattern.matches("(" + atom + "\\s?\\,?\\s?){1,}", data)) {
            // ^ bare numbers                                // ^ multiple objs
            return false;
        }

        return true;
    }
}

As you can see, this, my preferred solution, actually breaks the problem up into a couple steps: first, we make sure what the user entered begins with '[' and ends with ']', and then we make sure that the other stuff is a bare tuple, or a collection of such tuples. Again, there are nicer-looking ways of writing these regexen, and there are more terse ways to write them. But this way is maintainable. And, it passes all the tests you put forth for Ad sizes.

I've left Image sizes as an exercise for you, since it is very similar to Ad sizes.

I hope this helps.

Upvotes: 1

Related Questions