[Bf-blender-cvs] [7f2b4c871ea] master: WM: batch rename, regular expression support

Campbell Barton noreply at git.blender.org
Mon Sep 2 07:24:06 CEST 2019


Commit: 7f2b4c871ea9d93ad50e32326c9c1292d8104e2f
Author: Campbell Barton
Date:   Mon Sep 2 15:18:07 2019 +1000
Branches: master
https://developer.blender.org/rB7f2b4c871ea9d93ad50e32326c9c1292d8104e2f

WM: batch rename, regular expression support

Find/Replace can now use regular expressions.

===================================================================

M	release/scripts/startup/bl_operators/wm.py

===================================================================

diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py
index c20edced0f1..f7b4a4e80e6 100644
--- a/release/scripts/startup/bl_operators/wm.py
+++ b/release/scripts/startup/bl_operators/wm.py
@@ -1815,7 +1815,11 @@ class BatchRenameAction(bpy.types.PropertyGroup):
     # type: 'REPLACE'.
     replace_src: StringProperty(name="Find")
     replace_dst: StringProperty(name="Replace")
-    replace_match_case: BoolProperty(name="Match Case")
+    replace_match_case: BoolProperty(name="Case Sensitive")
+    replace_regex: BoolProperty(
+        name="Regular Expression",
+        description="Use regular expressions to match text in the 'Find' field"
+    )
 
     # type: 'CASE'.
     case_method: EnumProperty(
@@ -1844,16 +1848,16 @@ class WM_OT_batch_rename(Operator):
             ('OBJECT', "Objects", ""),
             ('MATERIAL', "Materials", ""),
             None,
-            # Match object types.
-            ('MESH', "Meshs", ""),
+            # Enum identifiers are compared with 'object.type'.
+            ('MESH', "Meshes", ""),
             ('CURVE', "Curves", ""),
-            ('META', "MetaBalls", ""),
+            ('META', "Meta Balls", ""),
             ('ARMATURE', "Armatures", ""),
             ('LATTICE', "Lattices", ""),
             ('GPENCIL', "Grease Pencils", ""),
             ('CAMERA', "Cameras", ""),
             ('SPEAKER', "Speakers", ""),
-            ('LIGHT_PROBE', "LightProbes", ""),
+            ('LIGHT_PROBE', "Light Probes", ""),
             None,
             ('BONE', "Bones", ""),
             ('NODE', "Nodes", ""),
@@ -2025,18 +2029,19 @@ class WM_OT_batch_rename(Operator):
                     name = name.rstrip(chars_strip)
 
             elif ty == 'REPLACE':
-                if action.replace_match_case:
-                    name = name.replace(
-                        action.replace_src,
-                        action.replace_dst,
-                    )
+                if action.replace_regex:
+                    replace_src = action.replace_src
                 else:
-                    name = re.sub(
-                        re.escape(action.replace_src),
-                        re.escape(action.replace_dst),
-                        name,
-                        flags=re.IGNORECASE,
-                    )
+                    replace_src = re.escape(action.replace_src)
+                name = re.sub(
+                    replace_src,
+                    re.escape(action.replace_dst),
+                    name,
+                    flags=(
+                        0 if action.replace_match_case else
+                        re.IGNORECASE
+                    ),
+                )
             elif ty == 'CASE':
                 method = action.case_method
                 if method == 'UPPER':
@@ -2063,14 +2068,17 @@ class WM_OT_batch_rename(Operator):
         self._data_type_prev = self.data_type
 
     def draw(self, context):
+        import re
+
         layout = self.layout
 
-        row = layout.row()
-        row.prop(self, "data_type")
+        split = layout.split(factor=0.5)
+        split.label(text="Data Type:")
+        split.prop(self, "data_type", text="")
 
-        row = layout.row()
-        row.label(text="Rename {:d} {:s}".format(len(self._data[0]), self._data[2]))
-        row.prop(self, "data_source", expand=True)
+        split = layout.split(factor=0.5)
+        split.label(text="Rename {:d} {:s}:".format(len(self._data[0]), self._data[2]))
+        split.row().prop(self, "data_source", expand=True)
 
         for action in self.actions:
             box = layout.box()
@@ -2088,9 +2096,23 @@ class WM_OT_batch_rename(Operator):
                 box.row().prop(action, "strip_chars")
                 box.row().prop(action, "strip_part")
             elif ty == 'REPLACE':
-                box.row().prop(action, "replace_src")
+
+                row = box.row()
+                re_error = None
+                if action.replace_regex:
+                    try:
+                        re.compile(action.replace_src)
+                    except Exception as ex:
+                        row.alert = True
+                        re_error = str(ex)
+                row.prop(action, "replace_src")
+                if re_error is not None:
+                    box.label(text=re_error)
+
                 box.row().prop(action, "replace_dst")
-                box.row().prop(action, "replace_match_case")
+                row = box.row()
+                row.prop(action, "replace_match_case")
+                row.prop(action, "replace_regex")
             elif ty == 'CASE':
                 box.row().prop(action, "case_method", expand=True)
 
@@ -2121,10 +2143,21 @@ class WM_OT_batch_rename(Operator):
         return changed
 
     def execute(self, context):
+        import re
+
         seq, attr, descr = self._data
 
         actions = self.actions
 
+        # Sanitize actions.
+        for action in actions:
+            if action.replace_regex:
+                try:
+                    re.compile(action.replace_src)
+                except Exception as ex:
+                    self.report({'ERROR'}, "Invalid regular expression: " + str(ex))
+                    return {'CANCELLED'}
+
         total_len = 0
         change_len = 0
         for item in seq:



More information about the Bf-blender-cvs mailing list