NOTE: this commit is missing the changes to the eventDetectors.jsp file.
Those changes to follow.

Code Changes:

Create class AlphanumericRegexStateDetectorRT:
/* 
	Copyright (C) 2013 Infinite Automation. All rights reserved.
	@author Phillip Dunlap
*/
package com.serotonin.m2m2.rt.event.detectors;

import java.util.regex.Pattern;

import com.serotonin.m2m2.i18n.TranslatableMessage;
import com.serotonin.m2m2.rt.dataImage.PointValueTime;
import com.serotonin.m2m2.view.text.TextRenderer;
import com.serotonin.m2m2.vo.event.PointEventDetectorVO;

public class AlphanumericRegexStateDetectorRT extends StateDetectorRT { 
    public AlphanumericRegexStateDetectorRT(PointEventDetectorVO vo) {
        this.vo = vo;
    }

    @Override
    public TranslatableMessage getMessage() {
        String name = vo.njbGetDataPoint().getName();
        String prettyText = vo.njbGetDataPoint().getTextRenderer()
                .getText(vo.getAlphanumericState(),
TextRenderer.HINT_SPECIFIC);
        TranslatableMessage durationDescription =
getDurationDescription();

        if (durationDescription != null)
            return new TranslatableMessage("event.detector.periodState",
name, prettyText, durationDescription);
        return new TranslatableMessage("event.detector.state", name,
prettyText);
    }

    @Override
    protected boolean stateDetected(PointValueTime newValue) {
        String newAlpha = newValue.getStringValue();
        if(newAlpha != null)
        	return
Pattern.compile(vo.getAlphanumericState()).matcher(newAlpha).find();
        return false;
    }
}


PointEventDetectorVO:
1. Add to line 79: d.add(new
ImplDefinition(TYPE_ALPHANUMERIC_REGEX_STATE, null,
"pointEdit.detectors.regexState", new int[] { DataTypes.ALPHANUMERIC
}));
2. Add case to line 135 switch: case TYPE_ALPHANUMERIC_REGEX_STATE:
            return new AlphanumericRegexStateDetectorRT(this);
3. Add case to ifs ~220: else if (detectorType ==
TYPE_ALPHANUMERIC_REGEX_STATE)
            message = new
TranslatableMessage("pointEdit.detectors.regexState", durationDesc);
4. Add type_code ~410:
TYPE_CODES.addElement(TYPE_ALPHANUMERIC_REGEX_STATE,
"ALPHANUMERIC_REGEX_STATE");
5. JSON write case ~450: case TYPE_ALPHANUMERIC_REGEX_STATE:
            writer.writeEntry("state", alphanumericState);
            addDuration(writer);
            break;
6. JSON read: case TYPE_ALPHANUMERIC_REGEX_STATE:
            alphanumericState = getString(jsonObject, "state");
            updateDuration(jsonObject);
            break;



DataPointEditDwr:
1. Add method to update detector ~297: @DwrPermission(user = true)
    public void updateAlphanumericRegexStateDetector(int pedId, String
xid, String alias, String state, int duration,
            int durationType, int alarmLevel) {
        PointEventDetectorVO ped = getEventDetector(pedId);
        ped.setXid(xid);
        ped.setAlias(alias);
        ped.setAlphanumericState(state);
        ped.setDuration(duration);
        ped.setDurationType(durationType);
        ped.setAlarmLevel(alarmLevel);
    }



eventDetector.jsp:
1. Add html for our new detector style, ~370: <tbody id="detectorType<%=
PointEventDetectorVO.TYPE_ALPHANUMERIC_REGEX_STATE %>">
      <tr><td class="horzSeparator" colspan="2"></td></tr>
      <tr>
        <td class="formLabelRequired">
          <tag:img png="delete" title="common.delete"
onclick="pointEventDetectorEditor.deleteDetector(getPedId(this))"/>
          <fmt:message key="pointEdit.detectors.type"/>
        </td>
        <td class="formField"><fmt:message
key="pointEdit.detectors.stateDet"/></td>
      </tr>
      <tr>
        <td class="formLabelRequired"><fmt:message
key="common.xid"/></td>
        <td class="formField"><input id="eventDetector_TEMPLATE_Xid"
type="text" class="formLong"/></td>
      </tr>
      <tr>
        <td class="formLabel"><fmt:message
key="pointEdit.detectors.alias"/></td>
        <td class="formField"><input id="eventDetector_TEMPLATE_Alias"
type="text" class="formLong"/></td>
      </tr>
      <tr>
        <td class="formLabelRequired"><fmt:message
key="common.alarmLevel"/></td>
        <td class="formField">
          <tag:alarmLevelOptions id="eventDetector_TEMPLATE_AlarmLevel"
                  onchange="pointEventDetectorEditor.updateAlarmLevelImage(this.value,
getPedId(this))"/>
          <tag:img id="eventDetector_TEMPLATE_AlarmLevelImg"
png="flag_green" title="common.alarmLevel.none" style="display:none;"/>
        </td>
      </tr>
      <tr>
        <td class="formLabelRequired"><fmt:message
key="pointEdit.detectors.state"/></td>
        <td class="formField"><input id="eventDetector_TEMPLATE_State"
type="text" class="formLong"/></td>
      </tr>
      <tr>
        <td class="formLabel"><fmt:message
key="pointEdit.detectors.duration"/></td>
        <td class="formField">
          <input id="eventDetector_TEMPLATE_Duration" type="text"
class="formShort"/>
          <tag:timePeriods id="eventDetector_TEMPLATE_DurationType"
s="true" min="true" h="true" d="true"/>
        </td>
      </tr>
      <tr><td class="formError" id="eventDetector_TEMPLATE_ErrorMessage"
colspan="2"></td></tr>
    </tbody>

2. Add Callback if case, ~560: else if (detector.detectorType == <%=
PointEventDetectorVO.TYPE_ALPHANUMERIC_REGEX_STATE %>) {
              $set("eventDetector"+ detector.id +"State",
detector.alphanumericState);
              $set("eventDetector"+ detector.id +"Duration",
detector.duration);
              $set("eventDetector"+ detector.id +"DurationType",
detector.durationType);
          }

3. Add Save error cases ~750:
else if (pedType == <%=
PointEventDetectorVO.TYPE_ALPHANUMERIC_REGEX_STATE %>) {
                  var state = $get("eventDetector"+ pedId +"State");
                  var duration = parseInt($get("eventDetector"+ pedId
+"Duration"));
                  var durationType = parseInt($get("eventDetector"+
pedId +"DurationType"));
                  
                  if (state && state.length > 128)
                      errorMessage = "<fmt:message
key="pointEdit.detectors.invalidState"/>";
                  else if (isNaN(duration))
                      errorMessage = "<fmt:message
key="pointEdit.detectors.errorParsingDuration"/>";
                  else if (duration < 0)
                      errorMessage = "<fmt:message
key="pointEdit.detectors.invalidDuration"/>";
                  else {
                      saveCBCount++;
                      DataPointEditDwr.updateAlphanumericRegexStateDetector(pedId,
xid, alias, state, duration, durationType, 
                              alarmLevel, saveCB);
                  }
              }


i18n_Properties:
1. Add regexState translation ~802: pointEdit.detectors.regexState=Regex
2. Add to message.jsp


Extensions: Currently Mango will either send the Regex or the alias if
there is one. This is acceptable, but it'd be really cool to be able to
access the match or capture groups in the freemarker model in the
future.