Rework shit to use v12345 instead of v[1]
Why did I even do that...
This commit is contained in:
110
main.go
110
main.go
@@ -34,10 +34,10 @@ func main() {
|
|||||||
// Define flags
|
// Define flags
|
||||||
flag.Usage = func() {
|
flag.Usage = func() {
|
||||||
fmt.Fprintf(os.Stderr, "Usage: %s <regex_with_capture_groups> <lua_expression> <...files>\n", os.Args[0])
|
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 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, " 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")
|
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, "/") ||
|
if strings.HasPrefix(luaExpr, "*") || strings.HasPrefix(luaExpr, "/") ||
|
||||||
strings.HasPrefix(luaExpr, "+") || strings.HasPrefix(luaExpr, "-") ||
|
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]
|
// Replace shorthand v1, v2, etc. with their direct variable names (no need for array notation)
|
||||||
shorthandRegex := regexp.MustCompile(`\bv(\d+)\b`)
|
// Note: we're keeping this regex in case the user writes v[1] style, but we'll convert it to v1
|
||||||
luaExpr = shorthandRegex.ReplaceAllString(luaExpr, "v[$1]")
|
shorthandRegex := regexp.MustCompile(`\bv\[(\d+)\]\b`)
|
||||||
|
luaExpr = shorthandRegex.ReplaceAllString(luaExpr, "v$1")
|
||||||
|
|
||||||
// Add custom script header with helper functions
|
// Add custom script header with helper functions
|
||||||
scriptHeader := `
|
scriptHeader := `
|
||||||
@@ -104,24 +106,24 @@ function floor(x) return math.floor(x) end
|
|||||||
function ceil(x) return math.ceil(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
|
var fullScript string
|
||||||
if strings.Contains(luaExpr, "v[1] =") || strings.Contains(luaExpr, "v[2] =") ||
|
if strings.Contains(luaExpr, "v1 =") || strings.Contains(luaExpr, "v2 =") ||
|
||||||
strings.Contains(luaExpr, "return") {
|
strings.Contains(luaExpr, "v3 =") || strings.Contains(luaExpr, "return") {
|
||||||
// Already has assignments, use as is
|
// Already has assignments, use as is
|
||||||
fullScript = fmt.Sprintf(`%s
|
fullScript = fmt.Sprintf(`%s
|
||||||
function process(v)
|
function process(...)
|
||||||
%s
|
%s
|
||||||
return v
|
return v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
|
||||||
end
|
end
|
||||||
`, scriptHeader, luaExpr)
|
`, scriptHeader, luaExpr)
|
||||||
} else {
|
} else {
|
||||||
// Simple expression, capture the result and assign to v[1]
|
// Simple expression, assign to v1
|
||||||
fullScript = fmt.Sprintf(`%s
|
fullScript = fmt.Sprintf(`%s
|
||||||
function process(v)
|
function process(...)
|
||||||
local result = %s
|
local result = %s
|
||||||
v[1] = result
|
v1 = result
|
||||||
return v
|
return v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12
|
||||||
end
|
end
|
||||||
`, scriptHeader, luaExpr)
|
`, scriptHeader, luaExpr)
|
||||||
}
|
}
|
||||||
@@ -178,58 +180,64 @@ func process(data string, pattern *regexp.Regexp, luaScript string) (string, err
|
|||||||
return match
|
return match
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a Lua table with the captured values
|
// Set up global variables v1, v2, etc.
|
||||||
vTable := L.NewTable()
|
|
||||||
for i, capture := range captures[1:] {
|
for i, capture := range captures[1:] {
|
||||||
// Convert each capture to float if possible
|
// Convert each capture to float if possible
|
||||||
floatVal, err := strconv.ParseFloat(capture, 64)
|
floatVal, err := strconv.ParseFloat(capture, 64)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
L.RawSetInt(vTable, i+1, lua.LNumber(floatVal))
|
L.SetGlobal(fmt.Sprintf("v%d", i+1), lua.LNumber(floatVal))
|
||||||
} else {
|
} 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(L.GetGlobal("process"))
|
||||||
L.Push(vTable)
|
if err := L.PCall(0, 12, nil); err != nil { // We're returning up to 12 values
|
||||||
if err := L.PCall(1, 1, nil); err != nil {
|
|
||||||
Error.Printf("Error executing Lua script: %v", err)
|
Error.Printf("Error executing Lua script: %v", err)
|
||||||
return match // Return unchanged on error
|
return match // Return unchanged on error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the result table
|
// Get the return values (up to 12)
|
||||||
resultTable := L.Get(-1)
|
returnValues := make([]lua.LValue, 12)
|
||||||
L.Pop(1)
|
for i := 0; i < 12; i++ {
|
||||||
|
// Get the value from the stack (if exists)
|
||||||
if tbl, ok := resultTable.(*lua.LTable); ok {
|
if L.GetTop() >= i+1 {
|
||||||
// Prepare to replace each capture group
|
returnValues[i] = L.Get(-12 + i)
|
||||||
result := match
|
} else {
|
||||||
for i := 1; i <= len(captures)-1; i++ {
|
returnValues[i] = lua.LNil
|
||||||
oldVal := captures[i]
|
}
|
||||||
|
}
|
||||||
// Get new value from Lua
|
// Pop all return values
|
||||||
luaVal := tbl.RawGetInt(i)
|
L.Pop(L.GetTop())
|
||||||
var newVal string
|
|
||||||
|
// Replace each capture group with its new value (if available)
|
||||||
switch v := luaVal.(type) {
|
result := match
|
||||||
case lua.LNumber:
|
for i := 0; i < len(captures)-1 && i < 12; i++ {
|
||||||
newVal = strconv.FormatFloat(float64(v), 'f', -1, 64)
|
if returnValues[i] == lua.LNil {
|
||||||
case lua.LString:
|
continue // Skip if nil return
|
||||||
newVal = string(v)
|
}
|
||||||
default:
|
|
||||||
newVal = fmt.Sprintf("%v", v)
|
oldVal := captures[i+1]
|
||||||
}
|
var newVal string
|
||||||
|
|
||||||
// Replace old value with new value
|
switch v := returnValues[i].(type) {
|
||||||
result = strings.Replace(result, oldVal, newVal, 1)
|
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 result
|
||||||
return match
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if !modified {
|
if !modified {
|
||||||
|
81
main_test.go
81
main_test.go
@@ -97,7 +97,7 @@ func TestArrayNotation(t *testing.T) {
|
|||||||
`
|
`
|
||||||
|
|
||||||
regex := regexp.MustCompile(`(?s)<value>(\d+)</value>`)
|
regex := regexp.MustCompile(`(?s)<value>(\d+)</value>`)
|
||||||
luaExpr := `v[1] * 1.5`
|
luaExpr := `v1 * 1.5`
|
||||||
luaScript := buildLuaScript(luaExpr)
|
luaScript := buildLuaScript(luaExpr)
|
||||||
|
|
||||||
modifiedContent, err := process(fileContents, regex, luaScript)
|
modifiedContent, err := process(fileContents, regex, luaScript)
|
||||||
@@ -215,7 +215,7 @@ func TestModifyingMultipleValues(t *testing.T) {
|
|||||||
`
|
`
|
||||||
|
|
||||||
regex := regexp.MustCompile(`(?s)<value>(\d+)</value>.*?<multiplier>(\d+)</multiplier>.*?<divider>(\d+)</divider>`)
|
regex := regexp.MustCompile(`(?s)<value>(\d+)</value>.*?<multiplier>(\d+)</multiplier>.*?<divider>(\d+)</divider>`)
|
||||||
luaExpr := `v[1] = v[1] * v[2] / v[3]; v[2] = min(v[2] * 2, 5); v[3] = max(1, v[3] / 2)`
|
luaExpr := `v1 = v1 * v2 / v3; v2 = min(v2 * 2, 5); v3 = max(1, v3 / 2)`
|
||||||
luaScript := buildLuaScript(luaExpr)
|
luaScript := buildLuaScript(luaExpr)
|
||||||
|
|
||||||
// Verify the regex matches before processing
|
// Verify the regex matches before processing
|
||||||
@@ -327,7 +327,7 @@ func TestProcessingSampleFiles(t *testing.T) {
|
|||||||
name: "Complex file - multiply values by multiplier and divide by divider",
|
name: "Complex file - multiply values by multiplier and divide by divider",
|
||||||
fileContent: string(complexFile),
|
fileContent: string(complexFile),
|
||||||
regexPattern: `(?s)<value>(\d+)</value>.*?<multiplier>(\d+)</multiplier>.*?<divider>(\d+)</divider>`,
|
regexPattern: `(?s)<value>(\d+)</value>.*?<multiplier>(\d+)</multiplier>.*?<divider>(\d+)</divider>`,
|
||||||
luaExpr: `v[1] * v[2] / v[3]`,
|
luaExpr: `v1 * v2 / v3`,
|
||||||
expectedFunc: func(content string) string {
|
expectedFunc: func(content string) string {
|
||||||
// Replace values manually for verification
|
// Replace values manually for verification
|
||||||
r := regexp.MustCompile(`(?s)<item>\s*<value>150</value>\s*<multiplier>2</multiplier>\s*<divider>4</divider>\s*</item>`)
|
r := regexp.MustCompile(`(?s)<item>\s*<value>150</value>\s*<multiplier>2</multiplier>\s*<divider>4</divider>\s*</item>`)
|
||||||
@@ -421,7 +421,7 @@ func TestFileOperations(t *testing.T) {
|
|||||||
|
|
||||||
// Configure test
|
// Configure test
|
||||||
regexPattern := `(?s)<value>(\d+)</value>.*?<multiplier>(\d+)</multiplier>.*?<divider>(\d+)</divider>`
|
regexPattern := `(?s)<value>(\d+)</value>.*?<multiplier>(\d+)</multiplier>.*?<divider>(\d+)</divider>`
|
||||||
luaExpr := `v[1] * v[2] / v[3]`
|
luaExpr := `v1 * v2 / v3`
|
||||||
|
|
||||||
// Execute test
|
// Execute test
|
||||||
regex := regexp.MustCompile(regexPattern)
|
regex := regexp.MustCompile(regexPattern)
|
||||||
@@ -517,3 +517,76 @@ func TestFileOperations(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHigherVariableIndices(t *testing.T) {
|
||||||
|
fileContents := `
|
||||||
|
<config>
|
||||||
|
<item>
|
||||||
|
<value1>10</value1>
|
||||||
|
<value2>20</value2>
|
||||||
|
<value3>30</value3>
|
||||||
|
<value4>40</value4>
|
||||||
|
<value5>50</value5>
|
||||||
|
<value11>110</value11>
|
||||||
|
</item>
|
||||||
|
</config>
|
||||||
|
`
|
||||||
|
|
||||||
|
// Test using v3, v4, v5 in the expression
|
||||||
|
t.Run("Using v3-v5 variables", func(t *testing.T) {
|
||||||
|
regex := regexp.MustCompile(`(?s)<value1>(\d+)</value1>.*?<value2>(\d+)</value2>.*?<value3>(\d+)</value3>.*?<value4>(\d+)</value4>.*?<value5>(\d+)</value5>`)
|
||||||
|
luaExpr := `v1 + v2 * v3 / v4 - v5`
|
||||||
|
luaScript := buildLuaScript(luaExpr)
|
||||||
|
|
||||||
|
// Expected: 10 + 20 * 30 / 40 - 50 = 10 + 15 - 50 = -25
|
||||||
|
|
||||||
|
modifiedContent, err := process(fileContents, regex, luaScript)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing with v3-v5: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The result should replace the first value
|
||||||
|
if !strings.Contains(modifiedContent, "<value1>-25</value1>") {
|
||||||
|
t.Fatalf("Failed to process v3-v5 correctly. Expected <value1>-25</value1>, got: %s", modifiedContent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test using v11 (double digit index)
|
||||||
|
// For double digit indexes, we need to capture it as the second variable (v2)
|
||||||
|
t.Run("Using v11 variable", func(t *testing.T) {
|
||||||
|
regex := regexp.MustCompile(`(?s)<value1>(\d+)</value1>.*?<value11>(\d+)</value11>`)
|
||||||
|
luaExpr := `v1 * v2`
|
||||||
|
luaScript := buildLuaScript(luaExpr)
|
||||||
|
|
||||||
|
// Expected: 10 * 110 = 1100
|
||||||
|
|
||||||
|
modifiedContent, err := process(fileContents, regex, luaScript)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing with v11: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// The result should replace the first value
|
||||||
|
if !strings.Contains(modifiedContent, "<value1>1100</value1>") {
|
||||||
|
t.Fatalf("Failed to process v11 correctly. Expected <value1>1100</value1>, got: %s", modifiedContent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Test using v0 (zero index)
|
||||||
|
t.Run("Using v0 variable", func(t *testing.T) {
|
||||||
|
// For this test, we'll capture the tag content and manipulate it
|
||||||
|
regex := regexp.MustCompile(`(?s)<value1>(\d+)</value1>`)
|
||||||
|
luaExpr := `tonumber(v1) * 2`
|
||||||
|
luaScript := buildLuaScript(luaExpr)
|
||||||
|
|
||||||
|
// This should double the value
|
||||||
|
modifiedContent, err := process(fileContents, regex, luaScript)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("Error processing with v0: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should replace <value1>10</value1> with <value1>20</value1>
|
||||||
|
if !strings.Contains(modifiedContent, "<value1>20</value1>") {
|
||||||
|
t.Fatalf("Failed to process test correctly. Expected <value1>20</value1>, got: %s", modifiedContent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user