Rework shit to use v12345 instead of v[1]

Why did I even do that...
This commit is contained in:
2025-03-22 02:30:30 +01:00
parent 6b5bfa700a
commit 4694a5b9aa
3 changed files with 137 additions and 55 deletions

110
main.go
View File

@@ -34,10 +34,10 @@ func main() {
// Define flags
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage: %s <regex_with_capture_groups> <lua_expression> <...files>\n", os.Args[0])
fmt.Fprintf(os.Stderr, "Example: %s \"<value>(\\d+)</value>,(\\d+)\" \"v[1] * 1.5 * v[2]\" data.xml\n", os.Args[0])
fmt.Fprintf(os.Stderr, "Example: %s \"<value>(\\d+)</value>,(\\d+)\" \"v1 * 1.5 * v2\" data.xml\n", os.Args[0])
fmt.Fprintf(os.Stderr, " or simplified: %s \"<value>(\\d+)</value>,(\\d+)\" \"v1 * 1.5 * v2\" data.xml\n", os.Args[0])
fmt.Fprintf(os.Stderr, " or even simpler: %s \"<value>(\\d+)</value>\" \"*1.5\" data.xml\n", os.Args[0])
fmt.Fprintf(os.Stderr, "\nNote: v1, v2, etc. are shortcuts for v[1], v[2], etc.\n")
fmt.Fprintf(os.Stderr, "\nNote: v1, v2, etc. are used to refer to capture groups.\n")
fmt.Fprintf(os.Stderr, " If expression starts with an operator like *, /, +, -, etc., v1 is automatically prepended\n")
}
@@ -87,12 +87,14 @@ func buildLuaScript(luaExpr string) string {
if strings.HasPrefix(luaExpr, "*") || strings.HasPrefix(luaExpr, "/") ||
strings.HasPrefix(luaExpr, "+") || strings.HasPrefix(luaExpr, "-") ||
strings.HasPrefix(luaExpr, "^") || strings.HasPrefix(luaExpr, "%") {
luaExpr = "v[1]" + luaExpr
luaExpr = "v1" + luaExpr
log.Printf("Expression modified to: %s", luaExpr)
}
// Replace shorthand v1, v2, etc. with v[1], v[2]
shorthandRegex := regexp.MustCompile(`\bv(\d+)\b`)
luaExpr = shorthandRegex.ReplaceAllString(luaExpr, "v[$1]")
// Replace shorthand v1, v2, etc. with their direct variable names (no need for array notation)
// Note: we're keeping this regex in case the user writes v[1] style, but we'll convert it to v1
shorthandRegex := regexp.MustCompile(`\bv\[(\d+)\]\b`)
luaExpr = shorthandRegex.ReplaceAllString(luaExpr, "v$1")
// Add custom script header with helper functions
scriptHeader := `
@@ -104,24 +106,24 @@ function floor(x) return math.floor(x) end
function ceil(x) return math.ceil(x) end
`
// Check if the expression already has assignments or a return statement
// Generate the full script
var fullScript string
if strings.Contains(luaExpr, "v[1] =") || strings.Contains(luaExpr, "v[2] =") ||
strings.Contains(luaExpr, "return") {
if strings.Contains(luaExpr, "v1 =") || strings.Contains(luaExpr, "v2 =") ||
strings.Contains(luaExpr, "v3 =") || strings.Contains(luaExpr, "return") {
// Already has assignments, use as is
fullScript = fmt.Sprintf(`%s
function process(v)
function process(...)
%s
return v
return v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
end
`, scriptHeader, luaExpr)
} else {
// Simple expression, capture the result and assign to v[1]
// Simple expression, assign to v1
fullScript = fmt.Sprintf(`%s
function process(v)
function process(...)
local result = %s
v[1] = result
return v
v1 = result
return v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
end
`, scriptHeader, luaExpr)
}
@@ -178,58 +180,64 @@ func process(data string, pattern *regexp.Regexp, luaScript string) (string, err
return match
}
// Create a Lua table with the captured values
vTable := L.NewTable()
// Set up global variables v1, v2, etc.
for i, capture := range captures[1:] {
// Convert each capture to float if possible
floatVal, err := strconv.ParseFloat(capture, 64)
if err == nil {
L.RawSetInt(vTable, i+1, lua.LNumber(floatVal))
L.SetGlobal(fmt.Sprintf("v%d", i+1), lua.LNumber(floatVal))
} else {
L.RawSetInt(vTable, i+1, lua.LString(capture))
L.SetGlobal(fmt.Sprintf("v%d", i+1), lua.LString(capture))
}
}
// Call the Lua function with the table
// Call the Lua function
L.Push(L.GetGlobal("process"))
L.Push(vTable)
if err := L.PCall(1, 1, nil); err != nil {
if err := L.PCall(0, 12, nil); err != nil { // We're returning up to 12 values
Error.Printf("Error executing Lua script: %v", err)
return match // Return unchanged on error
}
// Get the result table
resultTable := L.Get(-1)
L.Pop(1)
if tbl, ok := resultTable.(*lua.LTable); ok {
// Prepare to replace each capture group
result := match
for i := 1; i <= len(captures)-1; i++ {
oldVal := captures[i]
// Get new value from Lua
luaVal := tbl.RawGetInt(i)
var newVal string
switch v := luaVal.(type) {
case lua.LNumber:
newVal = strconv.FormatFloat(float64(v), 'f', -1, 64)
case lua.LString:
newVal = string(v)
default:
newVal = fmt.Sprintf("%v", v)
}
// Replace old value with new value
result = strings.Replace(result, oldVal, newVal, 1)
// Get the return values (up to 12)
returnValues := make([]lua.LValue, 12)
for i := 0; i < 12; i++ {
// Get the value from the stack (if exists)
if L.GetTop() >= i+1 {
returnValues[i] = L.Get(-12 + i)
} else {
returnValues[i] = lua.LNil
}
}
// Pop all return values
L.Pop(L.GetTop())
// Replace each capture group with its new value (if available)
result := match
for i := 0; i < len(captures)-1 && i < 12; i++ {
if returnValues[i] == lua.LNil {
continue // Skip if nil return
}
oldVal := captures[i+1]
var newVal string
switch v := returnValues[i].(type) {
case lua.LNumber:
newVal = strconv.FormatFloat(float64(v), 'f', -1, 64)
case lua.LString:
newVal = string(v)
default:
newVal = fmt.Sprintf("%v", v)
}
// If we have a value, replace it
if newVal != "" {
result = strings.Replace(result, oldVal, newVal, 1)
modified = true
}
modified = true
return result
}
// If something went wrong, return the original match
return match
return result
})
if !modified {