Repository: apache/streampipes
Pull request #3288 (2024-10-07 13:50:04)

feat(#3282): regex based preprocessing rule to adapters
<!--
  ~ Licensed to the Apache Software Foundation (ASF) under one or more
  ~ contributor license agreements.  See the NOTICE file distributed with
  ~ this work for additional information regarding copyright ownership.
  ~ The ASF licenses this file to You under the Apache License, Version 2.0
  ~ (the "License"); you may not use this file except in compliance with
  ~ the License.  You may obtain a copy of the License at
  ~
  ~    http://www.apache.org/licenses/LICENSE-2.0
  ~
  ~ Unless required by applicable law or agreed to in writing, software
  ~ distributed under the License is distributed on an "AS IS" BASIS,
  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  ~ See the License for the specific language governing permissions and
  ~ limitations under the License.
  ~
  -->

  <!--
Thanks for contributing! Here are some tips you can follow to help us incorporate your contribution quickly and easily:
1. If this is your first time, please read our contributor guidelines:
    - https://streampipes.apache.org/community/get-involved/
    - https://cwiki.apache.org/confluence/display/STREAMPIPES/Getting+Started
2. Make sure the PR title is formatted like: `[#<GitHub issue id>] PR title ...`
3. If the PR is unfinished, add '[WIP]' in your PR title, e.g., `[WIP][#<GitHub issue id>] PR title ...`.
4. Please write your PR title to summarize what this PR proposes/fixes.
5. Link the PR to the corresponding GitHub issue (if present) in the `Development` section in the right menu bar.
6. Be sure to keep the PR description updated to reflect all changes.
7. If possible, provide a concise example to reproduce the issue for a faster review.
8. Make sure tests pass via `mvn clean install`.
9. (Optional) If the contribution is large, please file an Apache ICLA
    - http://apache.org/licenses/icla.pdf
-->

### Purpose
<!--
Please clarify what changes you are proposing and describe how those changes will address the issue.
Furthermore, describe potential consequences the changes might have.
-->
This PR introduces a new preprocessing rule to Connect, allowing users to define a regex-based preprocessing rule for string event properties.
<img width="751" alt="grafik" src="https://github.com/user-attachments/assets/f30fcea7-7616-4d8b-a1b3-f22fb9ff6a02">


### Remarks
<!--
Is there anything left we need to pay attention on?
Are there some references that might be important? E.g. links to Confluence, or discussions
on the mailing list or GitHub.
-->
PR introduces (a) breaking change(s): no

PR introduces (a) deprecation(s): no



Patch:
diff --git a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverter.java b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverter.java
index 8e2381d506..100029741a 100644
--- a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverter.java
+++ b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverter.java
@@ -30,6 +30,7 @@ import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescript
 import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 import org.apache.streampipes.model.schema.EventProperty;
@@ -90,6 +91,11 @@ public class ToOriginalSchemaConverter implements ITransformationRuleVisitor, Pr
     property.setRuntimeName(rule.getOldRuntimeKey());
   }
 
+  @Override
+  public void visit(RegexTransformationRuleDescription rule) {
+    // does not affect schema
+  }
+
   @Override
   public void visit(EventRateTransformationRuleDescription rule) {
     // does not affect schema
diff --git a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverter.java b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverter.java
index 8ea159406f..00dcd7cc43 100644
--- a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverter.java
+++ b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverter.java
@@ -31,6 +31,7 @@ import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescript
 import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 import org.apache.streampipes.model.schema.EventProperty;
@@ -95,6 +96,7 @@ public class ToTransformedSchemaConverter implements ITransformationRuleVisitor,
     property.setRuntimeName(rule.getNewRuntimeKey());
   }
 
+
   @Override
   public void visit(EventRateTransformationRuleDescription rule) {
     // does not affect schema
@@ -149,6 +151,16 @@ public class ToTransformedSchemaConverter implements ITransformationRuleVisitor,
     metadata.put("correctionValue", rule.getCorrectionValue());
   }
 
+  @Override
+  public void visit(RegexTransformationRuleDescription rule) {
+    var property = findPrimitiveProperty(properties, rule.getRuntimeKey());
+    var metadata = property.getAdditionalMetadata();
+
+    metadata.put("regex", rule.getRegex());
+    metadata.put("replaceWith", rule.getReplaceWith());
+    metadata.put("replaceAll", rule.isReplaceAll());
+  }
+
   @Override
   public void visit(TimestampTranfsformationRuleDescription rule) {
     var property = findPrimitiveProperty(properties, rule.getRuntimeKey());
diff --git a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/generator/StatefulTransformationRuleGeneratorVisitor.java b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/generator/StatefulTransformationRuleGeneratorVisitor.java
index c8e3c4cb5d..b1d9c0956c 100644
--- a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/generator/StatefulTransformationRuleGeneratorVisitor.java
+++ b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/generator/StatefulTransformationRuleGeneratorVisitor.java
@@ -30,6 +30,7 @@ import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescript
 import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 
@@ -55,6 +56,11 @@ public class StatefulTransformationRuleGeneratorVisitor extends TransformationRu
     // skip (not a stateful transformation)
   }
 
+  @Override
+  public void visit(RegexTransformationRuleDescription rule) {
+    // skip (not a stateful transformation)
+  }
+
   @Override
   public void visit(EventRateTransformationRuleDescription ruleDesc) {
     rules.add(
diff --git a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/generator/StatelessTransformationRuleGeneratorVisitor.java b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/generator/StatelessTransformationRuleGeneratorVisitor.java
index 1728d8db27..1ca7d68dbd 100644
--- a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/generator/StatelessTransformationRuleGeneratorVisitor.java
+++ b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/generator/StatelessTransformationRuleGeneratorVisitor.java
@@ -26,6 +26,7 @@ import org.apache.streampipes.connect.shared.preprocessing.transform.schema.Rena
 import org.apache.streampipes.connect.shared.preprocessing.transform.value.AddTimestampTransformationRule;
 import org.apache.streampipes.connect.shared.preprocessing.transform.value.CorrectionValueTransformationRule;
 import org.apache.streampipes.connect.shared.preprocessing.transform.value.DatatypeTransformationRule;
+import org.apache.streampipes.connect.shared.preprocessing.transform.value.RegexTransformationRule;
 import org.apache.streampipes.connect.shared.preprocessing.transform.value.TimestampTranformationRuleMode;
 import org.apache.streampipes.connect.shared.preprocessing.transform.value.TimestampTransformationRule;
 import org.apache.streampipes.connect.shared.preprocessing.transform.value.UnitTransformationRule;
@@ -40,6 +41,7 @@ import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescript
 import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 
@@ -71,6 +73,15 @@ public class StatelessTransformationRuleGeneratorVisitor extends TransformationR
         Utils.getLastKey(ruleDesc.getNewRuntimeKey())));
   }
 
+  @Override
+  public void visit(RegexTransformationRuleDescription rule) {
+    rules.add(new RegexTransformationRule(
+        Utils.toKeyArray(rule.getRuntimeKey()),
+        rule.getRegex(),
+        rule.getReplaceWith(),
+        rule.isReplaceAll()));
+  }
+
   @Override
   public void visit(EventRateTransformationRuleDescription ruleDesc) {
     // Do nothing
diff --git a/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/transform/value/RegexTransformationRule.java b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/transform/value/RegexTransformationRule.java
new file mode 100644
index 0000000000..83c27c9068
--- /dev/null
+++ b/streampipes-connect-shared/src/main/java/org/apache/streampipes/connect/shared/preprocessing/transform/value/RegexTransformationRule.java
@@ -0,0 +1,70 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.connect.shared.preprocessing.transform.value;
+
+import org.apache.streampipes.connect.shared.preprocessing.SupportsNestedTransformationRule;
+
+import java.util.List;
+import java.util.Map;
+
+public class RegexTransformationRule extends SupportsNestedTransformationRule {
+
+  private final List<String> eventKeys;
+  private final String regex;
+  private final String replaceWith;
+  private final boolean replaceAll;
+
+  public RegexTransformationRule(
+      List<String> eventKeys,
+      String regex,
+      String replaceWith,
+      boolean replaceAll
+  ) {
+    this.eventKeys = eventKeys;
+    this.regex = regex;
+    this.replaceWith = replaceWith;
+    this.replaceAll = replaceAll;
+  }
+
+  @Override
+  protected List<String> getEventKeys() {
+    return eventKeys;
+  }
+
+  @Override
+  protected void applyTransformation(Map<String, Object> event, List<String> eventKey) {
+    var oldValue = event.get(eventKey.get(0));
+
+    var newValue = "";
+
+    if (oldValue instanceof String oldStringValue) {
+
+      if (this.replaceAll) {
+        newValue = oldStringValue.replaceAll(regex, this.replaceWith);
+      } else {
+        newValue = oldStringValue.replaceFirst(regex, this.replaceWith);
+      }
+
+      event.put(eventKey.get(0), newValue);
+    } else {
+      // add empty string if key is not present or wrong data type
+      event.put(eventKey.get(0), newValue);
+    }
+  }
+}
diff --git a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/TransformationRuleUpdateVisitor.java b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/TransformationRuleUpdateVisitor.java
index ef357e4c48..9661b7705c 100644
--- a/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/TransformationRuleUpdateVisitor.java
+++ b/streampipes-extensions-management/src/main/java/org/apache/streampipes/extensions/management/connect/TransformationRuleUpdateVisitor.java
@@ -31,6 +31,7 @@ import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescript
 import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 import org.apache.streampipes.model.schema.EventProperty;
@@ -80,6 +81,13 @@ public class TransformationRuleUpdateVisitor implements ITransformationRuleVisit
     }
   }
 
+  @Override
+  public void visit(RegexTransformationRuleDescription rule) {
+    if (containsKey(rule.getRuntimeKey())) {
+      validRules.add(rule);
+    }
+  }
+
   @Override
   public void visit(EventRateTransformationRuleDescription rule) {
     // Do nothing
diff --git a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/OpcUaConnectorsModuleExport.java b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/OpcUaConnectorsModuleExport.java
index d551d979d0..63aacdab58 100644
--- a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/OpcUaConnectorsModuleExport.java
+++ b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/OpcUaConnectorsModuleExport.java
@@ -25,6 +25,7 @@ import org.apache.streampipes.extensions.api.pe.IStreamPipesPipelineElement;
 import org.apache.streampipes.extensions.connectors.opcua.adapter.OpcUaAdapter;
 import org.apache.streampipes.extensions.connectors.opcua.migration.OpcUaAdapterMigrationV1;
 import org.apache.streampipes.extensions.connectors.opcua.migration.OpcUaAdapterMigrationV2;
+import org.apache.streampipes.extensions.connectors.opcua.migration.OpcUaAdapterMigrationV3;
 import org.apache.streampipes.extensions.connectors.opcua.sink.OpcUaSink;
 
 import java.util.List;
@@ -48,7 +49,8 @@ public class OpcUaConnectorsModuleExport implements IExtensionModuleExport {
   public List<IModelMigrator<?, ?>> migrators() {
     return List.of(
         new OpcUaAdapterMigrationV1(),
-        new OpcUaAdapterMigrationV2()
+        new OpcUaAdapterMigrationV2(),
+        new OpcUaAdapterMigrationV3()
     );
   }
 }
diff --git a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaAdapter.java b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaAdapter.java
index 5978f5ad24..baf5cfe95b 100644
--- a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaAdapter.java
+++ b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/adapter/OpcUaAdapter.java
@@ -74,6 +74,7 @@ import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaUtil
 public class OpcUaAdapter implements StreamPipesAdapter, IPullAdapter, SupportsRuntimeConfig {
 
   public static final String ID = "org.apache.streampipes.connect.iiot.adapters.opcua";
+  public static final String PULL_GROUP = "pull-mode-group";
   private static final Logger LOG = LoggerFactory.getLogger(OpcUaAdapter.class);
 
   private int pullingIntervalMilliSeconds;
@@ -154,17 +155,23 @@ public class OpcUaAdapter implements StreamPipesAdapter, IPullAdapter, SupportsR
           this.event.put(this.allNodes.get(i).getLabel(), value);
         } else {
           badStatusCodeReceived = true;
-          LOG.warn("Received status code {} for node label: {} - event will not be sent",
+          LOG.warn("Received status code {} for node label: {}",
               status,
               this.allNodes.get(i).getLabel());
         }
       }
     }
-    if (!badStatusCodeReceived && !emptyValueReceived) {
+    if (!emptyValueReceived && !shouldSkipEvent(badStatusCodeReceived)) {
       collector.collect(this.event);
     }
   }
 
+  private boolean shouldSkipEvent(boolean badStatusCodeReceived) {
+    return badStatusCodeReceived
+        && this.spOpcUaClient.getSpOpcConfig().getIncompleteEventStrategy()
+        .equalsIgnoreCase(SharedUserConfiguration.INCOMPLETE_OPTION_IGNORE);
+  }
+
   public void onSubscriptionValue(UaMonitoredItem item,
                                   DataValue value) {
 
@@ -231,14 +238,14 @@ public class OpcUaAdapter implements StreamPipesAdapter, IPullAdapter, SupportsR
 
   @Override
   public IAdapterConfiguration declareConfig() {
-    var builder = AdapterConfigurationBuilder.create(ID, 2, OpcUaAdapter::new)
+    var builder = AdapterConfigurationBuilder.create(ID, 3, OpcUaAdapter::new)
         .withAssets(ExtensionAssetType.DOCUMENTATION, ExtensionAssetType.ICON)
         .withLocales(Locales.EN)
         .withCategory(AdapterType.Generic, AdapterType.Manufacturing)
         .requiredAlternatives(Labels.withId(ADAPTER_TYPE),
             Alternatives.from(Labels.withId(PULL_MODE),
-                StaticProperties.integerFreeTextProperty(
-                    Labels.withId(PULLING_INTERVAL))),
+                SharedUserConfiguration.getPullModeGroup()
+            ),
             Alternatives.from(Labels.withId(SUBSCRIPTION_MODE)));
     SharedUserConfiguration.appendSharedOpcUaConfig(builder, true);
     return builder.buildConfiguration();
diff --git a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/OpcUaAdapterConfig.java b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/OpcUaAdapterConfig.java
index c6736ff8c3..e2758c8c03 100644
--- a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/OpcUaAdapterConfig.java
+++ b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/OpcUaAdapterConfig.java
@@ -21,6 +21,7 @@ package org.apache.streampipes.extensions.connectors.opcua.config;
 public class OpcUaAdapterConfig extends OpcUaConfig {
 
   private Integer pullIntervalMilliSeconds;
+  private String incompleteEventStrategy;
 
   public Integer getPullIntervalMilliSeconds() {
     return pullIntervalMilliSeconds;
@@ -33,4 +34,12 @@ public class OpcUaAdapterConfig extends OpcUaConfig {
   public boolean inPullMode() {
     return pullIntervalMilliSeconds != null;
   }
+
+  public String getIncompleteEventStrategy() {
+    return incompleteEventStrategy;
+  }
+
+  public void setIncompleteEventStrategy(String incompleteEventStrategy) {
+    this.incompleteEventStrategy = incompleteEventStrategy;
+  }
 }
diff --git a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/SharedUserConfiguration.java b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/SharedUserConfiguration.java
index cb95919174..9b5f541071 100644
--- a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/SharedUserConfiguration.java
+++ b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/SharedUserConfiguration.java
@@ -18,6 +18,9 @@
 
 package org.apache.streampipes.extensions.connectors.opcua.config;
 
+import org.apache.streampipes.model.staticproperty.OneOfStaticProperty;
+import org.apache.streampipes.model.staticproperty.Option;
+import org.apache.streampipes.model.staticproperty.StaticPropertyGroup;
 import org.apache.streampipes.sdk.StaticProperties;
 import org.apache.streampipes.sdk.builder.AbstractConfigurablePipelineElementBuilder;
 import org.apache.streampipes.sdk.helpers.Alternatives;
@@ -25,6 +28,7 @@ import org.apache.streampipes.sdk.helpers.Labels;
 
 import java.util.List;
 
+import static org.apache.streampipes.extensions.connectors.opcua.adapter.OpcUaAdapter.PULL_GROUP;
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.ACCESS_MODE;
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.ADAPTER_TYPE;
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.AVAILABLE_NODES;
@@ -36,12 +40,17 @@ import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabe
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.OPC_SERVER_URL;
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.OPC_URL;
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.PASSWORD;
+import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.PULLING_INTERVAL;
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.UNAUTHENTICATED;
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.USERNAME;
 import static org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels.USERNAME_GROUP;
 
 public class SharedUserConfiguration {
 
+  public static final String INCOMPLETE_EVENT_HANDLING_KEY = "incomplete-event-handling";
+  public static final String INCOMPLETE_OPTION_IGNORE = "ignore-event";
+  public static final String INCOMPLETE_OPTION_SEND = "send-event";
+
   public static void appendSharedOpcUaConfig(AbstractConfigurablePipelineElementBuilder<?, ?> builder,
                                              boolean adapterConfig) {
 
@@ -81,6 +90,28 @@ public class SharedUserConfiguration {
         );
   }
 
+  public static StaticPropertyGroup getPullModeGroup() {
+    var group = StaticProperties.group(
+        Labels.withId(PULL_GROUP),
+        false,
+        StaticProperties.integerFreeTextProperty(
+            Labels.withId(PULLING_INTERVAL)),
+        getIncompleteEventConfig()
+    );
+    group.setHorizontalRendering(false);
+    return group;
+  }
+
+  public static OneOfStaticProperty getIncompleteEventConfig() {
+    return StaticProperties.singleValueSelection(
+      Labels.withId(INCOMPLETE_EVENT_HANDLING_KEY),
+        List.of(
+            new Option("Ignore (only complete messages are sent)", INCOMPLETE_OPTION_IGNORE),
+            new Option("Send (incomplete messages are sent)", INCOMPLETE_OPTION_SEND)
+        )
+    );
+  }
+
   public static List<String> getDependsOn(boolean adapterConfig) {
     return adapterConfig ? List.of(
         ADAPTER_TYPE.name(),
diff --git a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/SpOpcUaConfigExtractor.java b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/SpOpcUaConfigExtractor.java
index 26cae21569..6741a3e6f8 100644
--- a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/SpOpcUaConfigExtractor.java
+++ b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/config/SpOpcUaConfigExtractor.java
@@ -55,8 +55,12 @@ public class SpOpcUaConfigExtractor {
     if (usePullMode) {
       Integer pullIntervalSeconds =
           extractor.singleValueParameter(PULLING_INTERVAL.name(), Integer.class);
+      var incompleteEventStrategy = extractor.selectedSingleValueInternalName(
+          SharedUserConfiguration.INCOMPLETE_EVENT_HANDLING_KEY, String.class
+      );
 
       config.setPullIntervalMilliSeconds(pullIntervalSeconds);
+      config.setIncompleteEventStrategy(incompleteEventStrategy);
     }
 
     return config;
diff --git a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/migration/OpcUaAdapterMigrationV2.java b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/migration/OpcUaAdapterMigrationV2.java
index 382d1e3514..23d643acbb 100644
--- a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/migration/OpcUaAdapterMigrationV2.java
+++ b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/migration/OpcUaAdapterMigrationV2.java
@@ -20,6 +20,7 @@ package org.apache.streampipes.extensions.connectors.opcua.migration;
 
 import org.apache.streampipes.extensions.api.extractor.IStaticPropertyExtractor;
 import org.apache.streampipes.extensions.api.migration.IAdapterMigrator;
+import org.apache.streampipes.extensions.connectors.opcua.adapter.OpcUaAdapter;
 import org.apache.streampipes.model.connect.adapter.AdapterDescription;
 import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceTagPrefix;
 import org.apache.streampipes.model.migration.MigrationResult;
@@ -38,7 +39,7 @@ public class OpcUaAdapterMigrationV2 implements IAdapterMigrator {
   @Override
   public ModelMigratorConfig config() {
     return new ModelMigratorConfig(
-        "org.apache.streampipes.connect.iiot.adapters.opcua",
+        OpcUaAdapter.ID,
         SpServiceTagPrefix.ADAPTER,
         1,
         2
diff --git a/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/migration/OpcUaAdapterMigrationV3.java b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/migration/OpcUaAdapterMigrationV3.java
new file mode 100644
index 0000000000..051dfe5196
--- /dev/null
+++ b/streampipes-extensions/streampipes-connectors-opcua/src/main/java/org/apache/streampipes/extensions/connectors/opcua/migration/OpcUaAdapterMigrationV3.java
@@ -0,0 +1,68 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.extensions.connectors.opcua.migration;
+
+import org.apache.streampipes.extensions.api.extractor.IStaticPropertyExtractor;
+import org.apache.streampipes.extensions.api.migration.IAdapterMigrator;
+import org.apache.streampipes.extensions.connectors.opcua.adapter.OpcUaAdapter;
+import org.apache.streampipes.extensions.connectors.opcua.config.SharedUserConfiguration;
+import org.apache.streampipes.extensions.connectors.opcua.utils.OpcUaLabels;
+import org.apache.streampipes.model.connect.adapter.AdapterDescription;
+import org.apache.streampipes.model.extensions.svcdiscovery.SpServiceTagPrefix;
+import org.apache.streampipes.model.migration.MigrationResult;
+import org.apache.streampipes.model.migration.ModelMigratorConfig;
+import org.apache.streampipes.model.staticproperty.StaticPropertyAlternatives;
+import org.apache.streampipes.sdk.StaticProperties;
+import org.apache.streampipes.sdk.helpers.Labels;
+
+public class OpcUaAdapterMigrationV3 implements IAdapterMigrator {
+  @Override
+  public ModelMigratorConfig config() {
+    return new ModelMigratorConfig(
+        OpcUaAdapter.ID,
+        SpServiceTagPrefix.ADAPTER,
+        2,
+        3
+    );
+  }
+
+  @Override
+  public MigrationResult<AdapterDescription> migrate(AdapterDescription element, IStaticPropertyExtractor extractor) throws RuntimeException {
+    var oneOfProperty = SharedUserConfiguration.getIncompleteEventConfig();
+    oneOfProperty.getOptions().get(0).setSelected(true);
+    element.getConfig().forEach(sp -> {
+      if (sp.getInternalName().equalsIgnoreCase(OpcUaLabels.ADAPTER_TYPE.name())) {
+        var alternatives = (StaticPropertyAlternatives) sp;
+        var pullAlternative = alternatives.getAlternatives().get(0);
+        var pullInterval = pullAlternative.getStaticProperty();
+        var group = StaticProperties.group(
+            Labels.withId(OpcUaAdapter.PULL_GROUP),
+            false,
+            pullInterval,
+            oneOfProperty
+        );
+        group.setHorizontalRendering(false);
+        pullAlternative.setStaticProperty(
+            group
+        );
+      }
+    });
+    return MigrationResult.success(element);
+  }
+}
diff --git a/streampipes-extensions/streampipes-connectors-opcua/src/main/resources/org.apache.streampipes.connect.iiot.adapters.opcua/strings.en b/streampipes-extensions/streampipes-connectors-opcua/src/main/resources/org.apache.streampipes.connect.iiot.adapters.opcua/strings.en
index c874137625..995045ec7a 100644
--- a/streampipes-extensions/streampipes-connectors-opcua/src/main/resources/org.apache.streampipes.connect.iiot.adapters.opcua/strings.en
+++ b/streampipes-extensions/streampipes-connectors-opcua/src/main/resources/org.apache.streampipes.connect.iiot.adapters.opcua/strings.en
@@ -67,3 +67,6 @@ PULL_MODE.description=
 
 SUBSCRIPTION_MODE.title=Subscription mode
 SUBSCRIPTION_MODE.description=
+
+incomplete-event-handling.title=Incomplete Events
+incomplete-event-handling.description=Select how events with missing values (e.g., due to bad status codes) are handled.
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/ITransformationRuleVisitor.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/ITransformationRuleVisitor.java
index bb45ff0eaf..78dbd37da1 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/ITransformationRuleVisitor.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/ITransformationRuleVisitor.java
@@ -28,6 +28,7 @@ import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescript
 import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 
@@ -41,6 +42,8 @@ public interface ITransformationRuleVisitor {
 
   void visit(RenameRuleDescription rule);
 
+  void visit(RegexTransformationRuleDescription rule);
+
   void visit(EventRateTransformationRuleDescription rule);
 
   void visit(RemoveDuplicatesTransformationRuleDescription rule);
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRuleDescription.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRuleDescription.java
index 0ea2194456..94b1817e8f 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRuleDescription.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRuleDescription.java
@@ -28,6 +28,7 @@ import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescript
 import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 import org.apache.streampipes.model.shared.annotation.TsModel;
@@ -47,6 +48,7 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo;
     @JsonSubTypes.Type(CreateNestedRuleDescription.class),
     @JsonSubTypes.Type(DeleteRuleDescription.class),
     @JsonSubTypes.Type(RenameRuleDescription.class),
+    @JsonSubTypes.Type(RegexTransformationRuleDescription.class),
     @JsonSubTypes.Type(MoveRuleDescription.class),
     @JsonSubTypes.Type(ChangeDatatypeTransformationRuleDescription.class),
     @JsonSubTypes.Type(CorrectionValueTransformationRuleDescription.class),
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRulePriority.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRulePriority.java
index 3fcb8ba429..28458d81c8 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRulePriority.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/TransformationRulePriority.java
@@ -31,6 +31,7 @@ public enum TransformationRulePriority {
   CHANGE_UNIT(310),
   TIMESTAMP_TRANSFORMATION(320),
   CORRECTION_VALUE(330),
+  REGEX_TRANSFORMATION(331),
   CHANGE_DATATYPE(340),
 
   REMOVE_DUPLICATES(410),
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/RegexTransformationRuleDescription.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/RegexTransformationRuleDescription.java
new file mode 100644
index 0000000000..7dd9eed5c2
--- /dev/null
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/RegexTransformationRuleDescription.java
@@ -0,0 +1,75 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.model.connect.rules.value;
+
+import org.apache.streampipes.model.connect.rules.ITransformationRuleVisitor;
+import org.apache.streampipes.model.connect.rules.TransformationRulePriority;
+
+public class RegexTransformationRuleDescription extends ValueTransformationRuleDescription {
+
+  private String runtimeKey;
+  private String regex;
+  private String replaceWith;
+  private boolean replaceAll;
+
+  public RegexTransformationRuleDescription() {
+  }
+
+  @Override
+  public void accept(ITransformationRuleVisitor visitor) {
+    visitor.visit(this);
+  }
+
+  @Override
+  public int getRulePriority() {
+    return TransformationRulePriority.REGEX_TRANSFORMATION.getCode();
+  }
+
+  public String getRuntimeKey() {
+    return runtimeKey;
+  }
+
+  public void setRuntimeKey(String runtimeKey) {
+    this.runtimeKey = runtimeKey;
+  }
+
+  public String getRegex() {
+    return regex;
+  }
+
+  public void setRegex(String regex) {
+    this.regex = regex;
+  }
+
+  public String getReplaceWith() {
+    return replaceWith;
+  }
+
+  public void setReplaceWith(String replaceWith) {
+    this.replaceWith = replaceWith;
+  }
+
+  public boolean isReplaceAll() {
+    return replaceAll;
+  }
+
+  public void setReplaceAll(boolean replaceAll) {
+    this.replaceAll = replaceAll;
+  }
+}
diff --git a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/ValueTransformationRuleDescription.java b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/ValueTransformationRuleDescription.java
index dee07a2151..e1f6e495bb 100644
--- a/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/ValueTransformationRuleDescription.java
+++ b/streampipes-model/src/main/java/org/apache/streampipes/model/connect/rules/value/ValueTransformationRuleDescription.java
@@ -28,6 +28,7 @@ import com.fasterxml.jackson.annotation.JsonSubTypes;
     @JsonSubTypes.Type(TimestampTranfsformationRuleDescription.class),
     @JsonSubTypes.Type(UnitTransformRuleDescription.class),
     @JsonSubTypes.Type(CorrectionValueTransformationRuleDescription.class),
+    @JsonSubTypes.Type(RegexTransformationRuleDescription.class),
 })
 public abstract class ValueTransformationRuleDescription extends TransformationRuleDescription {
 
diff --git a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java
index 685db7ee03..fee35a57a3 100644
--- a/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java
+++ b/streampipes-storage-couchdb/src/main/java/org/apache/streampipes/storage/couchdb/serializer/GsonSerializer.java
@@ -35,6 +35,7 @@ import org.apache.streampipes.model.connect.rules.value.AddTimestampRuleDescript
 import org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 import org.apache.streampipes.model.grounding.TopicDefinition;
@@ -94,6 +95,8 @@ public class GsonSerializer {
 
     builder.registerTypeAdapterFactory(RuntimeTypeAdapterFactory.of(TransformationRuleDescription.class, "sourceType")
         .registerSubtype(RenameRuleDescription.class, "org.apache.streampipes.model.RenameRuleDescription")
+        .registerSubtype(RegexTransformationRuleDescription.class,
+                         "org.apache.streampipes.model.RegexTransformationRuleDescription")
         .registerSubtype(MoveRuleDescription.class, "org.apache.streampipes.model.MoveRuleDescription")
         .registerSubtype(DeleteRuleDescription.class, "org.apache.streampipes.model.DeleteRuleDescription")
         .registerSubtype(CreateNestedRuleDescription.class, "org.apache.streampipes.model.CreateNestedRuleDescription")
diff --git a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventProcessorRuntime.java b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventProcessorRuntime.java
index b9ce761f59..54d9a0d3e2 100644
--- a/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventProcessorRuntime.java
+++ b/streampipes-wrapper-standalone/src/main/java/org/apache/streampipes/wrapper/standalone/runtime/StandaloneEventProcessorRuntime.java
@@ -68,6 +68,9 @@ public class StandaloneEventProcessorRuntime extends StandalonePipelineElementRu
       var event = this.internalRuntimeParameters.makeEvent(runtimeParameters, rawEvent, sourceInfo);
       pipelineElement
           .onEvent(event, outputCollector);
+    } catch (IllegalArgumentException e) {
+      LOG.warn("A key could not be found - this can be due to an operation on a missing field.");
+      addLogEntry(e);
     } catch (RuntimeException e) {
       LOG.error("RuntimeException while processing event in {}", pipelineElement.getClass().getCanonicalName(), e);
       addLogEntry(e);
diff --git a/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllFalse.csv b/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllFalse.csv
new file mode 100644
index 0000000000..f951ba2245
--- /dev/null
+++ b/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllFalse.csv
@@ -0,0 +1,2 @@
+density;sensorId
+122.0;aensor01
diff --git a/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllTrue.csv b/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllTrue.csv
new file mode 100644
index 0000000000..cbff946483
--- /dev/null
+++ b/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllTrue.csv
@@ -0,0 +1,2 @@
+density;sensorId
+122.0;aenaor01
diff --git a/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllTrueWithEmptyString.csv b/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllTrueWithEmptyString.csv
new file mode 100644
index 0000000000..91547295c5
--- /dev/null
+++ b/ui/cypress/fixtures/connect/regexRule/expectedReplaceAllTrueWithEmptyString.csv
@@ -0,0 +1,2 @@
+density;sensorId
+122.0;enor01
diff --git a/ui/cypress/fixtures/connect/regexRule/input.csv b/ui/cypress/fixtures/connect/regexRule/input.csv
new file mode 100644
index 0000000000..78eb36e07f
--- /dev/null
+++ b/ui/cypress/fixtures/connect/regexRule/input.csv
@@ -0,0 +1,2 @@
+timestamp;density;sensorId
+1720018277000;122.0;sensor01
diff --git a/ui/cypress/support/utils/connect/ConnectEventSchemaUtils.ts b/ui/cypress/support/utils/connect/ConnectEventSchemaUtils.ts
index 6bcfe2b231..b8cdfeabeb 100644
--- a/ui/cypress/support/utils/connect/ConnectEventSchemaUtils.ts
+++ b/ui/cypress/support/utils/connect/ConnectEventSchemaUtils.ts
@@ -255,6 +255,10 @@ export class ConnectEventSchemaUtils {
         cy.get('#event-schema-next-button').parent().should('not.be.disabled');
     }
 
+    public static schemaPreviewResultEvent() {
+        return cy.dataCy('schema-preview-result-event', { timeout: 10000 });
+    }
+
     public static finishEventSchemaConfiguration() {
         // Click next
         cy.dataCy('sp-connect-schema-editor', { timeout: 10000 }).should(
@@ -270,7 +274,18 @@ export class ConnectEventSchemaUtils {
         ConnectEventSchemaUtils.validateRuntimeName(propertyName);
     }
 
-    //
+    public static regexValueInput() {
+        return cy.dataCy('regex-value');
+    }
+
+    public static regexReplaceWithValueInput() {
+        return cy.dataCy('regex-replace-with-value');
+    }
+
+    public static regexReplaceAllCheckbox() {
+        return cy.dataCy('regex-replace-all-value');
+    }
+
     /**
      * Function to escape special characters in a string for use in Cypress
      * selectors
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
index 4cbe0f01c0..68e4a75c60 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model-client.ts
@@ -16,11 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 3.2.1263 on 2024-09-08 22:18:46.
+// Generated using typescript-generator version 3.2.1263 on 2024-10-07 13:58:29.
 
 import { Storable } from './streampipes-model';
 
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
index 1ae8e4e32d..e5faa9118d 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/gen/streampipes-model.ts
@@ -16,11 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-
 /* tslint:disable */
 /* eslint-disable */
 // @ts-nocheck
-// Generated using typescript-generator version 3.2.1263 on 2024-09-30 14:11:40.
+// Generated using typescript-generator version 3.2.1263 on 2024-10-07 13:58:27.
 
 export class NamedStreamPipesEntity implements Storable {
     '@class':
@@ -209,6 +208,7 @@ export class TransformationRuleDescription {
         | 'org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription'
+        | 'org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.stream.StreamTransformationRuleDescription'
@@ -261,6 +261,8 @@ export class TransformationRuleDescription {
                 return DeleteRuleDescription.fromData(data);
             case 'org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription':
                 return RenameRuleDescription.fromData(data);
+            case 'org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription':
+                return RegexTransformationRuleDescription.fromData(data);
             case 'org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription':
                 return MoveRuleDescription.fromData(data);
             case 'org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription':
@@ -282,6 +284,7 @@ export class ValueTransformationRuleDescription extends TransformationRuleDescri
         | 'org.apache.streampipes.model.connect.rules.value.AddValueTransformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.value.TimestampTranfsformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription'
+        | 'org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.value.ChangeDatatypeTransformationRuleDescription'
         | 'org.apache.streampipes.model.connect.rules.value.CorrectionValueTransformationRuleDescription';
 
@@ -316,6 +319,8 @@ export class ValueTransformationRuleDescription extends TransformationRuleDescri
                 return CorrectionValueTransformationRuleDescription.fromData(
                     data,
                 );
+            case 'org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription':
+                return RegexTransformationRuleDescription.fromData(data);
         }
     }
 }
@@ -3061,6 +3066,30 @@ export class QuantitativeValue extends ValueSpecification {
     }
 }
 
+export class RegexTransformationRuleDescription extends ValueTransformationRuleDescription {
+    '@class': 'org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription';
+    'regex': string;
+    'replaceAll': boolean;
+    'replaceWith': string;
+    'runtimeKey': string;
+
+    static 'fromData'(
+        data: RegexTransformationRuleDescription,
+        target?: RegexTransformationRuleDescription,
+    ): RegexTransformationRuleDescription {
+        if (!data) {
+            return data;
+        }
+        const instance = target || new RegexTransformationRuleDescription();
+        super.fromData(data, instance);
+        instance.regex = data.regex;
+        instance.replaceAll = data.replaceAll;
+        instance.replaceWith = data.replaceWith;
+        instance.runtimeKey = data.runtimeKey;
+        return instance;
+    }
+}
+
 export class RemoveDuplicatesTransformationRuleDescription extends StreamTransformationRuleDescription {
     '@class': 'org.apache.streampipes.model.connect.rules.stream.RemoveDuplicatesTransformationRuleDescription';
     'filterTimeWindow': string;
@@ -4080,6 +4109,7 @@ export type TransformationRuleDescriptionUnion =
     | CreateNestedRuleDescription
     | DeleteRuleDescription
     | RenameRuleDescription
+    | RegexTransformationRuleDescription
     | MoveRuleDescription
     | ChangeDatatypeTransformationRuleDescription
     | CorrectionValueTransformationRuleDescription;
@@ -4100,7 +4130,8 @@ export type ValueTransformationRuleDescriptionUnion =
     | AddValueTransformationRuleDescription
     | TimestampTranfsformationRuleDescription
     | UnitTransformRuleDescription
-    | CorrectionValueTransformationRuleDescription;
+    | CorrectionValueTransformationRuleDescription
+    | RegexTransformationRuleDescription;
 
 function __getCopyArrayFn<T>(itemCopyFn: (item: T) => T): (array: T[]) => T[] {
     return (array: T[]) => __copyArray(array, itemCopyFn);
diff --git a/ui/projects/streampipes/platform-services/src/lib/model/types/data-type.ts b/ui/projects/streampipes/platform-services/src/lib/model/types/data-type.ts
index 077b9b9741..74e75ac9ea 100644
--- a/ui/projects/streampipes/platform-services/src/lib/model/types/data-type.ts
+++ b/ui/projects/streampipes/platform-services/src/lib/model/types/data-type.ts
@@ -41,4 +41,8 @@ export class DataType {
     public static isBooleanType(datatype: string): boolean {
         return datatype === DataType.BOOLEAN;
     }
+
+    public static isStringType(datatype: string): boolean {
+        return datatype === DataType.STRING;
+    }
 }
diff --git a/ui/src/app/connect/connect.module.ts b/ui/src/app/connect/connect.module.ts
index 0d0e598a31..f66f7edebb 100644
--- a/ui/src/app/connect/connect.module.ts
+++ b/ui/src/app/connect/connect.module.ts
@@ -104,6 +104,7 @@ import { AdapterStatusLightComponent } from './components/existing-adapters/adap
 import { SpAdapterDeploymentSettingsComponent } from './components/adapter-configuration/adapter-settings/adapter-deployment-settings/adapter-deployment-settings.component';
 import { SpAdapterDocumentationDialogComponent } from './dialog/adapter-documentation/adapter-documentation-dialog.component';
 import { AdapterDetailsDataComponent } from './components/adapter-details/adapter-details-data/adapter-details-data.component';
+import { EditRegexTransformationComponent } from './dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component';
 
 @NgModule({
     imports: [
@@ -204,6 +205,7 @@ import { AdapterDetailsDataComponent } from './components/adapter-details/adapte
         DeleteAdapterDialogComponent,
         EventSchemaComponent,
         EditEventPropertyComponent,
+        EditRegexTransformationComponent,
         EventPropertyRowComponent,
         EditUnitTransformationComponent,
         EditSchemaTransformationComponent,
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.html
new file mode 100644
index 0000000000..e75269a4c2
--- /dev/null
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.html
@@ -0,0 +1,52 @@
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one or more
+  ~ contributor license agreements.  See the NOTICE file distributed with
+  ~ this work for additional information regarding copyright ownership.
+  ~ The ASF licenses this file to You under the Apache License, Version 2.0
+  ~ (the "License"); you may not use this file except in compliance with
+  ~ the License.  You may obtain a copy of the License at
+  ~
+  ~    http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  ~
+  -->
+
+<div fxLayout="column" fxLayoutAlign="start">
+    <div fxFlex="50" fxLayoutAlign="start center">
+        <mat-form-field class="w-100" color="accent">
+            <input
+                matInput
+                type="text"
+                name="regex"
+                placeholder="Regular expression"
+                data-cy="regex-value"
+                [(ngModel)]="cachedProperty.additionalMetadata.regex"
+            />
+        </mat-form-field>
+    </div>
+    <div fxFlex="50" fxLayoutAlign="start center">
+        <mat-form-field class="w-100" color="accent">
+            <input
+                matInput
+                type="text"
+                name="replaceWith"
+                placeholder="Replace with"
+                data-cy="regex-replace-with-value"
+                [(ngModel)]="cachedProperty.additionalMetadata.replaceWith"
+            />
+        </mat-form-field>
+    </div>
+    <div fxFlex="50" fxLayoutAlign="start center">
+        <mat-checkbox
+            data-cy="regex-replace-all-value"
+            [(ngModel)]="cachedProperty.additionalMetadata.replaceAll"
+        >
+            <span>Replace All Occurrences</span>
+        </mat-checkbox>
+    </div>
+</div>
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.scss b/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.scss
new file mode 100644
index 0000000000..13cbc4aacb
--- /dev/null
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.scss
@@ -0,0 +1,17 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.ts
new file mode 100644
index 0000000000..f926738e0e
--- /dev/null
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-regex-transformation/edit-regex-transformation.component.ts
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+import { Component, Input } from '@angular/core';
+import { EventPropertyUnion } from '@streampipes/platform-services';
+
+@Component({
+    selector: 'sp-edit-regex-transformation',
+    templateUrl: './edit-regex-transformation.component.html',
+    styleUrl: './edit-regex-transformation.component.scss',
+})
+export class EditRegexTransformationComponent {
+    @Input() cachedProperty: EventPropertyUnion;
+}
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.html
index a7435e21b7..921d1b536f 100644
--- a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.html
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.html
@@ -39,7 +39,6 @@
                     [(ngModel)]="
                         cachedProperty.additionalMetadata.correctionValue
                     "
-                    (change)="valueChanged()"
                     data-cy="connect-schema-correction-value"
                 />
             </mat-form-field>
@@ -50,7 +49,6 @@
                     required
                     placeholder="Math Operator"
                     [(ngModel)]="cachedProperty.additionalMetadata.operator"
-                    (selectionChange)="valueChanged()"
                     [disabled]="
                         !cachedProperty.additionalMetadata.correctionValue
                     "
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.ts
index 1b16d86c85..68b5abce1e 100644
--- a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.ts
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-correction-value/edit-correction-value.component.ts
@@ -16,7 +16,7 @@
  *
  */
 
-import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { Component, Input } from '@angular/core';
 import { EventPropertyUnion } from '@streampipes/platform-services';
 
 @Component({
@@ -27,27 +27,10 @@ import { EventPropertyUnion } from '@streampipes/platform-services';
 export class EditCorrectionValueComponent {
     @Input() cachedProperty: EventPropertyUnion;
 
-    @Output() correctionValueChanged = new EventEmitter<boolean>();
-
     operators = [
         { value: 'MULTIPLY', viewValue: 'Multiply' },
         { value: 'ADD', viewValue: 'Add' },
         { value: 'SUBTRACT', viewValue: 'Subtract' },
         { value: 'DIVIDE', viewValue: 'Divide' },
     ];
-
-    constructor() {}
-
-    valueChanged() {
-        if (this.cachedProperty.additionalMetadata.correctionValue) {
-            if (!this.cachedProperty.additionalMetadata.operator) {
-                this.correctionValueChanged.emit(true);
-            } else {
-                this.correctionValueChanged.emit(false);
-            }
-        } else {
-            this.correctionValueChanged.emit(false);
-            this.cachedProperty.additionalMetadata.operator = undefined;
-        }
-    }
 }
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.html b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.html
index 5986d8137d..9cfb5cc517 100644
--- a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.html
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.html
@@ -60,4 +60,14 @@
             />
         </mat-form-field>
     </sp-ep-settings-section>
+    <sp-ep-settings-section
+        sectionTitle="Regex Value Transformation"
+        sectionDescription="Transforms the original field values using the provided regex"
+        fxLayout="column"
+        fxFlex="100"
+        *ngIf="isStringProperty"
+    >
+        <sp-edit-regex-transformation [cachedProperty]="cachedProperty">
+        </sp-edit-regex-transformation>
+    </sp-ep-settings-section>
 </div>
diff --git a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.ts b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.ts
index fd87bf99a1..73238f6d3c 100644
--- a/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.ts
+++ b/ui/src/app/connect/dialog/edit-event-property/components/edit-value-transformation/edit-value-transformation.component.ts
@@ -40,6 +40,7 @@ export class EditValueTransformationComponent implements OnInit {
     @Input() isListProperty: boolean;
     @Input() isPrimitiveProperty: boolean;
     @Input() isNumericProperty: boolean;
+    @Input() isStringProperty: boolean;
 
     addedByUser: boolean;
     staticValue: string;
diff --git a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.html b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.html
index 0fe15aea50..cc7aad6cad 100644
--- a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.html
+++ b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.html
@@ -82,6 +82,7 @@
                         [isNestedProperty]="isEventPropertyNested"
                         [isListProperty]="isEventPropertyList"
                         [isPrimitiveProperty]="isEventPropertyPrimitive"
+                        [isStringProperty]="isStringProperty"
                         #valueTransformationComponent
                     >
                     </sp-edit-value-transformation>
@@ -98,17 +99,6 @@
                     </sp-edit-unit-transformation>
                 </div>
             </form>
-
-            <!--            <sp-edit-event-property-primitive-->
-            <!--                    *ngIf="isEventPropertyPrimitive"-->
-            <!--                    [isTimestampProperty]="isTimestampProperty"-->
-            <!--                    [cachedProperty]="cachedProperty"-->
-            <!--                    (isNumericDataType)="isNumericDataType($event)">-->
-            <!--            </sp-edit-event-property-primitive>-->
-            <!--            <sp-edit-event-property-list-->
-            <!--                    *ngIf="isEventPropertyList"-->
-            <!--                    [cachedProperty]="cachedProperty">-->
-            <!--            </sp-edit-event-property-list>-->
         </div>
     </div>
     <mat-divider></mat-divider>
diff --git a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts
index 0cff8aefd4..ea7f191aca 100644
--- a/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts
+++ b/ui/src/app/connect/dialog/edit-event-property/edit-event-property.component.ts
@@ -66,6 +66,7 @@ export class EditEventPropertyComponent implements OnInit {
     isEventPropertyNested: boolean;
     isEventPropertyList: boolean;
     isNumericProperty: boolean;
+    isStringProperty: boolean;
     isSaveBtnEnabled: boolean;
 
     private propertyForm: UntypedFormGroup;
@@ -89,6 +90,9 @@ export class EditEventPropertyComponent implements OnInit {
         this.isNumericProperty =
             SemanticType.isNumber(this.cachedProperty) ||
             DataType.isNumberType((this.cachedProperty as any).runtimeType);
+        this.isStringProperty = DataType.isStringType(
+            (this.cachedProperty as any).runtimeType,
+        );
         this.createForm();
     }
 
@@ -116,6 +120,13 @@ export class EditEventPropertyComponent implements OnInit {
                     ep.additionalMetadata.formatString;
                 result.additionalMetadata.multiplier =
                     ep.additionalMetadata.multiplier;
+
+                result.additionalMetadata.regex =
+                    ep.additionalMetadata.regex || undefined;
+                result.additionalMetadata.replaceWith =
+                    ep.additionalMetadata.replaceWith || undefined;
+                result.additionalMetadata.replaceAll =
+                    ep.additionalMetadata.replaceAll || undefined;
             }
 
             (result as any).staticValue = (ep as any).staticValue;
@@ -177,6 +188,13 @@ export class EditEventPropertyComponent implements OnInit {
                 this.cachedProperty.additionalMetadata.correctionValue;
             this.property.additionalMetadata.operator =
                 this.cachedProperty.additionalMetadata.operator;
+
+            this.property.additionalMetadata.regex =
+                this.cachedProperty.additionalMetadata.regex;
+            this.property.additionalMetadata.replaceWith =
+                this.cachedProperty.additionalMetadata.replaceWith;
+            this.property.additionalMetadata.replaceAll =
+                this.cachedProperty.additionalMetadata.replaceAll;
         }
         this.dialogRef.close({ data: this.property });
         this.shepherdService.trigger('adapter-field-changed');
diff --git a/ui/src/app/connect/services/transformation-rule.service.ts b/ui/src/app/connect/services/transformation-rule.service.ts
index b79883961a..5d87c36d69 100644
--- a/ui/src/app/connect/services/transformation-rule.service.ts
+++ b/ui/src/app/connect/services/transformation-rule.service.ts
@@ -31,6 +31,7 @@ import {
     EventSchema,
     MoveRuleDescription,
     PropertyScope,
+    RegexTransformationRuleDescription,
     RenameRuleDescription,
     SemanticType,
     TimestampTranfsformationRuleDescription,
@@ -100,6 +101,13 @@ export class TransformationRuleService {
 
             // Scale
             transformationRuleDescriptions = transformationRuleDescriptions
+                .concat(
+                    this.getRegexTransformationRules(
+                        targetSchema.eventProperties,
+                        originalSchema,
+                        targetSchema,
+                    ),
+                )
                 .concat(
                     this.getCorrectionValueRules(
                         targetSchema.eventProperties,
@@ -671,4 +679,59 @@ export class TransformationRuleService {
 
         return filteredResult;
     }
+
+    private getRegexTransformationRules(
+        eventProperties: EventPropertyUnion[],
+        oldEventSchema: EventSchema,
+        newEventSchema: EventSchema,
+    ) {
+        const result: RegexTransformationRuleDescription[] = [];
+
+        eventProperties.forEach(eventProperty => {
+            if (eventProperty instanceof EventPropertyPrimitive) {
+                const newRuntimeName = this.getCompleteRuntimeNameKey(
+                    newEventSchema.eventProperties,
+                    eventProperty.elementId,
+                );
+
+                if (
+                    eventProperty.additionalMetadata?.regex &&
+                    eventProperty.additionalMetadata?.regex != ''
+                ) {
+                    const rule =
+                        this.createRegexTransformationRuleDescriptionFromEventProperty(
+                            newRuntimeName,
+                            eventProperty,
+                        );
+
+                    result.push(rule);
+                }
+            } else if (eventProperty instanceof EventPropertyNested) {
+                result.push(
+                    ...this.getRegexTransformationRules(
+                        eventProperty.eventProperties,
+                        oldEventSchema,
+                        newEventSchema,
+                    ),
+                );
+            }
+        });
+
+        return result;
+    }
+
+    private createRegexTransformationRuleDescriptionFromEventProperty(
+        newRuntimeName: string,
+        eventProperty: EventPropertyPrimitive,
+    ) {
+        const rule: RegexTransformationRuleDescription =
+            new RegexTransformationRuleDescription();
+        rule['@class'] =
+            'org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription';
+        rule.runtimeKey = newRuntimeName;
+        rule.regex = eventProperty.additionalMetadata.regex;
+        rule.replaceWith = eventProperty.additionalMetadata.replaceWith ?? '';
+        rule.replaceAll = eventProperty.additionalMetadata.replaceAll ?? false;
+        return rule;
+    }
 }


Test patch:
diff --git a/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/Helpers.java b/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/Helpers.java
index ca8dd0c347..a8e823a520 100644
--- a/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/Helpers.java
+++ b/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/Helpers.java
@@ -21,6 +21,7 @@ package org.apache.streampipes.connect.shared.preprocessing.convert;
 import org.apache.streampipes.model.connect.rules.schema.DeleteRuleDescription;
 import org.apache.streampipes.model.connect.rules.schema.MoveRuleDescription;
 import org.apache.streampipes.model.connect.rules.schema.RenameRuleDescription;
+import org.apache.streampipes.model.connect.rules.value.RegexTransformationRuleDescription;
 import org.apache.streampipes.model.connect.rules.value.UnitTransformRuleDescription;
 import org.apache.streampipes.model.schema.EventProperty;
 import org.apache.streampipes.model.schema.EventPropertyNested;
@@ -34,7 +35,8 @@ import java.util.List;
 public class Helpers {
 
   public static String getUnit(EventProperty eventProperty) {
-    return ((EventPropertyPrimitive) eventProperty).getMeasurementUnit().toString();
+    return ((EventPropertyPrimitive) eventProperty).getMeasurementUnit()
+                                                   .toString();
   }
 
   public static List<EventProperty> makeSimpleProperties(boolean addTimestamp) {
@@ -67,16 +69,35 @@ public class Helpers {
     return rule;
   }
 
-  public static MoveRuleDescription makeMoveTransformationRule(String runtimeKey,
-                                                         String newRuntimeKey) {
+  public static RegexTransformationRuleDescription makeRegexTransformationRule(
+      String runtimeKey,
+      String regex,
+      String replaceWith,
+      boolean replaceAll
+  ) {
+    var rule = new RegexTransformationRuleDescription();
+    rule.setRuntimeKey(runtimeKey);
+    rule.setRegex(regex);
+    rule.setReplaceWith(replaceWith);
+    rule.setReplaceAll(replaceAll);
+
+    return rule;
+  }
+
+  public static MoveRuleDescription makeMoveTransformationRule(
+      String runtimeKey,
+      String newRuntimeKey
+  ) {
     var rule = new MoveRuleDescription();
     rule.setOldRuntimeKey(runtimeKey);
     rule.setNewRuntimeKey(newRuntimeKey);
     return rule;
   }
 
-  public static RenameRuleDescription makeRenameTransformationRule(String runtimeKey,
-                                                             String newRuntimeName) {
+  public static RenameRuleDescription makeRenameTransformationRule(
+      String runtimeKey,
+      String newRuntimeName
+  ) {
     var rule = new RenameRuleDescription();
     rule.setOldRuntimeKey(runtimeKey);
     rule.setNewRuntimeKey(newRuntimeName);
diff --git a/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverterTest.java b/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverterTest.java
index 966ea56c84..e5f1e1ed3d 100644
--- a/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverterTest.java
+++ b/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToOriginalSchemaConverterTest.java
@@ -25,7 +25,6 @@ import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.sdk.helpers.EpProperties;
 import org.apache.streampipes.sdk.helpers.Labels;
 
-import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.util.ArrayList;
@@ -37,6 +36,7 @@ import static org.apache.streampipes.connect.shared.preprocessing.convert.Helper
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeNestedProperties;
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeSimpleProperties;
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeUnitTransformationRule;
+import static org.junit.jupiter.api.Assertions.assertEquals;
 
 public class ToOriginalSchemaConverterTest {
 
@@ -52,8 +52,8 @@ public class ToOriginalSchemaConverterTest {
 
     var resultProperties = executeAndReturnResult(properties, rules);
 
-    Assertions.assertEquals(3, resultProperties.size());
-    Assertions.assertEquals("originalUnit", getUnit(resultProperties.get(0)));
+    assertEquals(3, resultProperties.size());
+    assertEquals("originalUnit", getUnit(resultProperties.get(0)));
   }
 
   @Test
@@ -68,8 +68,8 @@ public class ToOriginalSchemaConverterTest {
     var nestedResultProperty = ((EventPropertyNested) resultProperties.get(1)).getEventProperties()
                                                                               .get(0);
 
-    Assertions.assertEquals(2, resultProperties.size());
-    Assertions.assertEquals("originalUnit", getUnit(nestedResultProperty));
+    assertEquals(2, resultProperties.size());
+    assertEquals("originalUnit", getUnit(nestedResultProperty));
   }
 
   @Test
@@ -84,13 +84,13 @@ public class ToOriginalSchemaConverterTest {
     rules.add(makeMoveTransformationRule("epToBeMoved", "nested"));
 
     var result = executeAndReturnResult(properties, rules);
-    Assertions.assertEquals(3, result.size());
-    Assertions.assertEquals(
+    assertEquals(3, result.size());
+    assertEquals(
         "timestamp",
         result.get(0)
               .getRuntimeName()
     );
-    Assertions.assertEquals(
+    assertEquals(
         2,
         ((EventPropertyNested) result.get(1)).getEventProperties()
                                              .size()
@@ -104,8 +104,8 @@ public class ToOriginalSchemaConverterTest {
 
     rules.add(makeDeleteTransformationRule("epToBeRestored"));
     var result = executeAndReturnResult(properties, rules);
-    Assertions.assertEquals(4, result.size());
-    Assertions.assertEquals(
+    assertEquals(4, result.size());
+    assertEquals(
         "epToBeRestored",
         result.get(3)
               .getRuntimeName()
diff --git a/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverterTest.java b/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverterTest.java
index 44443d151a..ab753dad24 100644
--- a/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverterTest.java
+++ b/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/convert/ToTransformedSchemaConverterTest.java
@@ -25,7 +25,6 @@ import org.apache.streampipes.model.schema.EventSchema;
 import org.apache.streampipes.sdk.helpers.EpProperties;
 import org.apache.streampipes.sdk.helpers.Labels;
 
-import org.junit.jupiter.api.Assertions;
 import org.junit.jupiter.api.Test;
 
 import java.util.ArrayList;
@@ -35,9 +34,12 @@ import static org.apache.streampipes.connect.shared.preprocessing.convert.Helper
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeDeleteTransformationRule;
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeMoveTransformationRule;
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeNestedProperties;
+import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeRegexTransformationRule;
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeRenameTransformationRule;
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeSimpleProperties;
 import static org.apache.streampipes.connect.shared.preprocessing.convert.Helpers.makeUnitTransformationRule;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
 
 public class ToTransformedSchemaConverterTest {
 
@@ -51,8 +53,27 @@ public class ToTransformedSchemaConverterTest {
 
     var resultProperties = executeAndReturnResult(properties, rules);
 
-    Assertions.assertEquals(3, resultProperties.size());
-    Assertions.assertEquals("targetUnit", getUnit(resultProperties.get(0)));
+    assertEquals(3, resultProperties.size());
+    assertEquals("targetUnit", getUnit(resultProperties.get(0)));
+  }
+
+
+  @Test
+  public void testRegexTransformationRule() {
+    List<EventProperty> properties = makeSimpleProperties(true);
+
+    var rules = new ArrayList<TransformationRuleDescription>();
+
+    rules.add(makeRegexTransformationRule("stringProp", ",", "", true));
+
+    var resultProperties = executeAndReturnResult(properties, rules);
+
+    assertEquals(3, resultProperties.size());
+
+    assertEquals(3, resultProperties.get(0).getAdditionalMetadata().size());
+    assertTrue(resultProperties.get(0).getAdditionalMetadata().containsKey("regex"));
+    assertTrue(resultProperties.get(0).getAdditionalMetadata().containsKey("replaceWith"));
+    assertTrue(resultProperties.get(0).getAdditionalMetadata().containsKey("replaceAll"));
   }
 
 
@@ -64,9 +85,12 @@ public class ToTransformedSchemaConverterTest {
     rules.add(makeRenameTransformationRule("stringProp", "newStringProp"));
 
     var result = executeAndReturnResult(properties, rules);
-    Assertions.assertEquals(3, result.size());
-    Assertions.assertEquals("newStringProp",
-                            result.get(0).getRuntimeName());
+    assertEquals(3, result.size());
+    assertEquals(
+        "newStringProp",
+        result.get(0)
+              .getRuntimeName()
+    );
   }
 
   @Test
@@ -77,9 +101,12 @@ public class ToTransformedSchemaConverterTest {
     rules.add(makeDeleteTransformationRule("stringProp"));
 
     var result = executeAndReturnResult(properties, rules);
-    Assertions.assertEquals(2, result.size());
-    Assertions.assertEquals("intProp",
-                            result.get(0).getRuntimeName());
+    assertEquals(2, result.size());
+    assertEquals(
+        "intProp",
+        result.get(0)
+              .getRuntimeName()
+    );
   }
 
   @Test
@@ -92,11 +119,17 @@ public class ToTransformedSchemaConverterTest {
     rules.add(makeMoveTransformationRule("epToBeMoved", "nested"));
 
     var result = executeAndReturnResult(properties, rules);
-    Assertions.assertEquals(2, result.size());
-    Assertions.assertEquals("timestamp",
-                            result.get(0).getRuntimeName());
-    Assertions.assertEquals(3,
-                            ((EventPropertyNested) result.get(1)).getEventProperties().size());
+    assertEquals(2, result.size());
+    assertEquals(
+        "timestamp",
+        result.get(0)
+              .getRuntimeName()
+    );
+    assertEquals(
+        3,
+        ((EventPropertyNested) result.get(1)).getEventProperties()
+                                             .size()
+    );
   }
 
   @Test
@@ -108,18 +141,20 @@ public class ToTransformedSchemaConverterTest {
     rules.add(makeUnitTransformationRule("nested<-=>stringProp"));
 
     var resultProperties = executeAndReturnResult(properties, rules);
-    var nestedResultProperty = ((EventPropertyNested) resultProperties.get(1)).getEventProperties().get(0);
+    var nestedResultProperty = ((EventPropertyNested) resultProperties.get(1)).getEventProperties()
+                                                                              .get(0);
 
-    Assertions.assertEquals(2, resultProperties.size());
-    Assertions.assertEquals("targetUnit", getUnit(nestedResultProperty));
+    assertEquals(2, resultProperties.size());
+    assertEquals("targetUnit", getUnit(nestedResultProperty));
   }
 
-  private List<EventProperty> executeAndReturnResult(List<EventProperty> properties,
-                                                     List<TransformationRuleDescription> rules) {
+  private List<EventProperty> executeAndReturnResult(
+      List<EventProperty> properties,
+      List<TransformationRuleDescription> rules
+  ) {
     var result = new SchemaConverter().toTransformedSchema(new EventSchema(properties), rules);
     return result.getEventProperties();
   }
 
 
-
 }
diff --git a/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/transform/value/RegexTransformationRuleTest.java b/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/transform/value/RegexTransformationRuleTest.java
new file mode 100644
index 0000000000..be7cb23a8d
--- /dev/null
+++ b/streampipes-connect-shared/src/test/java/org/apache/streampipes/connect/shared/preprocessing/transform/value/RegexTransformationRuleTest.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.streampipes.connect.shared.preprocessing.transform.value;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+class RegexTransformationRuleTest {
+  private static final String PROPERTY = "property";
+
+  private Map<String, Object> event;
+
+  @BeforeEach
+  public void setUp() {
+    event = new HashMap<>();
+  }
+
+  @Test
+  void applyTransformation_ReplaceAllComma() {
+    event.put(PROPERTY, "a,b,");
+    var rule = getRegexTransformationRule(",", "", true);
+
+    rule.apply(event);
+
+    assertEquals("ab", event.get(PROPERTY));
+  }
+
+  @Test
+  void applyTransformation_ReplaceOneComma() {
+    event.put(PROPERTY, "a,b,");
+    var rule = getRegexTransformationRule(",", "", false);
+
+    rule.apply(event);
+
+    assertEquals("ab,", event.get(PROPERTY));
+  }
+
+  @Test
+  void applyTransformation_NoReplacement() {
+    event.put(PROPERTY, "ab");
+    var rule = getRegexTransformationRule(",", "", false);
+
+    rule.apply(event);
+
+    assertEquals("ab", event.get(PROPERTY));
+  }
+
+  @Test
+  void applyTransformation_WrongDataType() {
+    event.put(PROPERTY, 5);
+    var rule = getRegexTransformationRule(",", "", false);
+
+    rule.apply(event);
+
+    assertEquals("", event.get(PROPERTY));
+  }
+
+  @Test
+  void applyTransformation_ValueNotPresent() {
+    var rule = getRegexTransformationRule(",", "", false);
+
+    rule.apply(event);
+
+    assertEquals("", event.get(PROPERTY));
+  }
+
+  private RegexTransformationRule getRegexTransformationRule(
+      String regex,
+      String replaceWith,
+      boolean replaceAll
+  ) {
+    return new RegexTransformationRule(List.of(PROPERTY), regex, replaceWith, replaceAll);
+  }
+}
\ No newline at end of file
diff --git a/ui/cypress/tests/connect/rules/deleteTransformationRule.spec.ts b/ui/cypress/tests/connect/rules/deleteTransformationRule.spec.ts
index ad558ab8d2..19efb96b46 100644
--- a/ui/cypress/tests/connect/rules/deleteTransformationRule.spec.ts
+++ b/ui/cypress/tests/connect/rules/deleteTransformationRule.spec.ts
@@ -37,7 +37,7 @@ describe('Connect delete rule transformation', () => {
         ConnectEventSchemaUtils.deleteProperty('reserved bit_1');
         ConnectEventSchemaUtils.deleteProperty('reserved bit_2');
 
-        cy.dataCy('schema-preview-result-event').should(
+        ConnectEventSchemaUtils.schemaPreviewResultEvent().should(
             'have.text',
             '{\u00A0\u00A0\u00A0\u00A0"timestamp":\u00A01715356080000}',
         );
@@ -69,7 +69,7 @@ describe('Connect delete rule transformation', () => {
         ConnectEventSchemaUtils.deleteProperty('child');
 
         // The resulting string contains non-breaking spaces character (\u00A0)
-        cy.dataCy('schema-preview-result-event').should(
+        ConnectEventSchemaUtils.schemaPreviewResultEvent().should(
             'have.text',
             '{\u00A0\u00A0\u00A0\u00A0"parent":\u00A0{\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0\u00A0"child_two":\u00A0"textTwo"\u00A0\u00A0\u00A0\u00A0},\u00A0\u00A0\u00A0\u00A0"timestamp":\u00A01667904471000}',
         );
@@ -78,7 +78,7 @@ describe('Connect delete rule transformation', () => {
 
         // Test to delete the parent property
         ConnectEventSchemaUtils.deleteProperty('parent');
-        cy.dataCy('schema-preview-result-event').should(
+        ConnectEventSchemaUtils.schemaPreviewResultEvent().should(
             'have.text',
 
             '{\u00A0\u00A0\u00A0\u00A0"timestamp":\u00A01667904471000}',
@@ -88,7 +88,7 @@ describe('Connect delete rule transformation', () => {
         ConnectEventSchemaUtils.deleteProperty('child');
         ConnectEventSchemaUtils.deleteProperty('child_two');
 
-        cy.dataCy('schema-preview-result-event').should(
+        ConnectEventSchemaUtils.schemaPreviewResultEvent().should(
             'have.text',
             '{\u00A0\u00A0\u00A0\u00A0"parent":\u00A0{},\u00A0\u00A0\u00A0\u00A0"timestamp":\u00A01667904471000}',
         );
@@ -97,7 +97,7 @@ describe('Connect delete rule transformation', () => {
 
         // Test to delete the parent property
         ConnectEventSchemaUtils.deleteProperty('parent');
-        cy.dataCy('schema-preview-result-event').should(
+        ConnectEventSchemaUtils.schemaPreviewResultEvent().should(
             'have.text',
 
             '{\u00A0\u00A0\u00A0\u00A0"timestamp":\u00A01667904471000}',
@@ -109,7 +109,7 @@ describe('Connect delete rule transformation', () => {
         ConnectEventSchemaUtils.deleteProperty('child');
         ConnectEventSchemaUtils.deleteProperty('child_two');
 
-        cy.dataCy('schema-preview-result-event').should(
+        ConnectEventSchemaUtils.schemaPreviewResultEvent().should(
             'have.text',
             '{\u00A0\u00A0\u00A0\u00A0"parent":\u00A0{},\u00A0\u00A0\u00A0\u00A0"timestamp":\u00A01667904471000}',
         );
diff --git a/ui/cypress/tests/connect/rules/regexRule.spec.ts b/ui/cypress/tests/connect/rules/regexRule.spec.ts
new file mode 100644
index 0000000000..c9ac4d194a
--- /dev/null
+++ b/ui/cypress/tests/connect/rules/regexRule.spec.ts
@@ -0,0 +1,107 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one or more
+ *  contributor license agreements.  See the NOTICE file distributed with
+ *  this work for additional information regarding copyright ownership.
+ *  The ASF licenses this file to You under the Apache License, Version 2.0
+ *  (the "License"); you may not use this file except in compliance with
+ *  the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ */
+
+import { ConnectUtils } from '../../../support/utils/connect/ConnectUtils';
+import { ConnectEventSchemaUtils } from '../../../support/utils/connect/ConnectEventSchemaUtils';
+import { ConnectBtns } from '../../../support/utils/connect/ConnectBtns';
+import { FileManagementUtils } from '../../../support/utils/FileManagementUtils';
+
+describe('Connect value rule transformations', () => {
+    beforeEach('Setup Test', () => {
+        cy.initStreamPipesTest();
+        FileManagementUtils.addFile('connect/regexRule/input.csv');
+    });
+
+    it('Perform Test Replace All True', () => {
+        runTest('aenaor01', 'a', true, 'expectedReplaceAllTrue.csv');
+    });
+
+    it('Perform Test Replace All False', () => {
+        runTest('aensor01', 'a', false, 'expectedReplaceAllFalse.csv');
+    });
+
+    it('Perform Test Replace With Empty String', () => {
+        runTest(
+            'enor01',
+            '',
+            true,
+            'expectedReplaceAllTrueWithEmptyString.csv',
+        );
+    });
+
+    function runTest(
+        expectedPreview: string,
+        replaceWith: string,
+        replaceAll: boolean,
+        expecedCsvFile: string,
+    ) {
+        const adapterConfiguration =
+            ConnectUtils.setUpPreprocessingRuleTest(false);
+
+        // Ensure regex input is not shown for number property
+        ConnectEventSchemaUtils.clickEditProperty('density');
+        ConnectEventSchemaUtils.regexValueInput().should('not.exist');
+        ConnectBtns.saveEditProperty().click();
+        ConnectEventSchemaUtils.clickEditProperty('sensorId');
+        ConnectEventSchemaUtils.regexValueInput().should('be.visible');
+
+        // Validate that preview works
+        ConnectEventSchemaUtils.regexValueInput().type('s');
+        if (replaceWith !== '') {
+            ConnectEventSchemaUtils.regexReplaceWithValueInput().type(
+                replaceWith,
+            );
+        }
+        if (replaceAll) {
+            ConnectEventSchemaUtils.regexReplaceAllCheckbox().click();
+        }
+
+        ConnectBtns.saveEditProperty().click();
+
+        ConnectEventSchemaUtils.schemaPreviewResultEvent().should(
+            'contain.text',
+            expectedPreview,
+        );
+        ConnectEventSchemaUtils.markPropertyAsTimestamp('timestamp');
+        ConnectEventSchemaUtils.finishEventSchemaConfiguration();
+
+        ConnectUtils.tearDownPreprocessingRuleTest(
+            adapterConfiguration,
+            'cypress/fixtures/connect/regexRule/' + expecedCsvFile,
+            true,
+        );
+    }
+});