I've had a look at How do I re.search or re.match on a whole file without reading it all into memory? and TypeError: sequence item 1: expected a bytes-like object, str found , but the solutions in those two questions have not worked for me.
So the goal of this is to do a regex search in the text file for a pattern, specifically from the example text file
ParameterValue = Texture2D'/Game/Characters/Slashers/Bear/Textures/Outfit01/T_BEHead01_BC.T_BEHead01_BC' ParameterValue = Texture2D'/Game/Characters/Slashers/Bear/Textures/Outfit01/T_BEHead01_BC.T_BEHead01_BC'
I want to extract "/Game/Characters/Slashers/Bear/Textures/Outfit01/T_BEHead01_BC" and "/Game/Characters/Slashers/Bear/Textures/Outfit01/T_BEHead01_BC" which I know to be the string regex pattern:
Texture2D\'(.*)\.
and part of the capture group .group(1) .
The relevant code section is:
with open(mytool.propstxt_path, 'r+') as f:
data = mmap.mmap(f.fileno(), 0)
match_obj = re.match('Texture2D\'(.*)\'', data)
print(match_obj.group(1))
and am using mmap to read the entire text file to memory so data acts like a normal string that can be regex matched.
However I'm getting a problem: cannot use a string like pattern on a bytes like object on this line: match_obj = re.match('Texture2D'(.*)'', data)
So I tried converting the string pattern to a bytes like pattern with regex and compile. But unfortunately this causes the match_obj to be nothing because printing it returns None, so I think the following code segment is incorrect.
with open(mytool.propstxt_path, 'r+') as f:
data = mmap.mmap(f.fileno(), 0)
regex = rb'Texture2D\'(.*)\''
pattern = re.compile(regex)
match_obj = re.match(pattern, data)#'Texture2D\'(.*)\''
print(match_obj)
I have also tried putting a b before the pattern to convert it to bytes, but this again causes the match_obj to be None with no attribute .group().
with open(mytool.propstxt_path, 'r+') as f:
data = mmap.mmap(f.fileno(), 0)
match_obj = re.match(b'Texture2D\'(.*)\'', data)
print(match_obj.group(1))
Final thing I've tried is decoding the data to UTF-8 using .decode(). by doing the following, but it returns an error mmap.mmap object has no attribute decode.
with open(mytool.propstxt_path, 'r+') as f:
data = mmap.mmap(f.fileno(), 0).decode('UTF-8')
match_obj = re.match('Texture2D\'(.*)\'', data)
print(match_obj.group(1))
The final thing I'm thinking of trying is just reading the whole file line by line as mmaps mean you need to use byte like regex which I don't know how to do in my case.
My whole code is the following, but a warning it is for a blender plugin, creating a panel and such.
#import all libraries including those needed for regex matching and mapping string to memory
import bpy, re, mmap
class PathProps(bpy.types.PropertyGroup):
propstxt_path: bpy.props.StringProperty(name="Select PropsTxt File ", description="Select a File", subtype="FILE_PATH")
texloc_path: bpy.props.StringProperty(name="Select Exported Game Folder ", description="Select a Folder", subtype="DIR_PATH")
class DBDShaderScript_PT_main_panel(bpy.types.Panel):
bl_label = "DBD Shader Maps"
bl_idname = "DBDShaderScript_PT_main_panel"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = "DBD Shaders"
def draw(self, context):
layout = self.layout
scene = context.scene
mytool = scene.my_tool
layout.prop(mytool, "propstxt_path")
layout.prop(mytool, "texloc_path")
layout.operator("dbdshaderscript.addbasic_operator")
class DBDShaderScript_OT_add_basic(bpy.types.Operator):
bl_label = "Add Basic Shader Map (Every Material Except Hair)"
bl_idname = "dbdshaderscript.addbasic_operator"
def execute(self, context):
#make reference to user inputted file name
scene = context.scene
mytool = scene.my_tool
#find the selected material, s_mat stands for selected material
s_mat = bpy.context.active_object.active_material
s_mat.use_nodes = True
#store new link function to variable
link = s_mat.node_tree.links.new
#assign Principled BSDF to a variable so can be referenced later
#so that nodes can link to it
principled_node = s_mat.node_tree.nodes.get('Principled BSDF')
#start adding all nodes and respective links to shader map
srgb_node = s_mat.node_tree.nodes.new("ShaderNodeSeparateRGB")
srgb_node.location = (-200,150) # x,y
link(srgb_node.outputs[2], principled_node.inputs[4])
node = s_mat.node_tree.nodes.new("ShaderNodeValToRGB")
node.location = (-500,50) # x,y
link(node.outputs[0], principled_node.inputs[7])
#node = s_mat.node_tree.nodes.new("ShaderNodeSeparateRGB")
#node.location = (-200,100) # x,y
#link(node.outputs[2], principled_node.inputs[4])
with open(mytool.propstxt_path, 'r+') as f:
data = mmap.mmap(f.fileno(), 0)
match_obj = re.match('Texture2D\'(.*)\'', data)
print(match_obj.group(1))
#add image texture nodes
texImage = s_mat.node_tree.nodes.new('ShaderNodeTexImage')
#example loading image
#texImage.image = bpy.data.images.load("C:\\Users\\myName\\Downloads\\Textures\\Downloaded\\flooring5.jpg")
#uncomment this
#texImage.image = bpy.data.images.load(match_obj.group(1)[0])
#make a link to principle BSDF node
link(texImage.outputs[0], principled_node.inputs[0])
return {"FINISHED"}
#register + unregister all classes with a loop
classes = [PathProps, DBDShaderScript_PT_main_panel, DBDShaderScript_OT_add_basic]
def register():
for cls in classes:
bpy.utils.register_class(cls)
#create pointer to all properties
bpy.types.Scene.my_tool = bpy.props.PointerProperty(type = PathProps)
def unregister():
for cls in classes:
bpy.utils.unregister_class(cls)
del bpy.types.Scene.my_tool
if __name__ == "__main__":
register()