Java代码字符串引号在NodeJS脚本处理中丢失的解决方案咨询
我最近碰到个头疼的问题,想请教各位帮忙捋捋:
我做了个NodeJS服务,接收用户传来的JSON对象,里面包含Java代码片段、测试用例、预期结果以及语言类型,比如这个示例输入:
{ "code": "class StringOperations {\n public String concatenate(String a, String b) {\n return a + b;\n }\n}", "tests": ["new StringOperations().concatenate(\"Hello\", \"world\")"], "expectedResults": ["Helloworld"], "language": "java" }
然后我用一个getJavaScript函数把这些内容拼接成可编译的Java主类代码,但生成后的代码出问题了——测试用例里的字符串引号直接丢失了!比如原本的new StringOperations().concatenate("Hello", "world"),生成后变成了:
String actualResult_0 = new StringOperations().concatenate(Hello, hello);
这直接导致Java编译报错,因为Hello和hello会被当成未定义的变量。我知道如果让用户把测试用例写成["new StringOperations().concatenate(\\\"Hello\\\", \\\"world\\\")"]这种带多层转义的格式能解决,但这样对用户太不友好了,而且其他语言的输入不需要这么做,所以我想找个不需要用户额外处理的解决方案。
我已经在处理预期结果的时候用了JSON.stringify(JSON.stringify(expectedResults[index]))来保留引号,但测试用例这块的处理没搞定,想问问有没有什么办法能让NodeJS在拼接代码时自动保留测试用例里的双引号?
可行解决方案
后来我琢磨出问题所在:从JSON解析出来的tests数组里的字符串,里面的双引号是未转义的原始状态,但当我们把它拼进Java代码字符串时,Java里的字符串需要用\"来表示双引号,所以我们需要在NodeJS里对测试用例字符串做一次转义处理。
修改getJavaScript函数里的测试用例拼接逻辑就可以解决:
export const getJavaScript = (code, tests, expectedResults) => ` import java.io.*; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.HashMap; import com.google.gson.Gson; import com.google.gson.JsonObject; import com.google.gson.JsonArray; ${code} public class Main { public static void main(String[] args) { java.util.List<java.util.Map<String, Object>> results = new java.util.ArrayList<>(); try { ${tests .map( (test, index) => ` String actualResult_${index} = ${test.replace(/"/g, '\\"')}; String expectedResult_${index} = ${JSON.stringify( JSON.stringify(expectedResults[index]), )}; java.util.Map<String, Object> testResult_${index} = new java.util.HashMap<>(); if (actualResult_${index}.equals(expectedResult_${index})) { testResult_${index}.put(\"success\", true); } else { testResult_${index}.put(\"success\", false); } testResult_${index}.put(\"actualResult\", actualResult_${index}); testResult_${index}.put(\"expectedResult\", expectedResult_${index}); results.add(testResult_${index}); `, ) .join('\n')} System.out.println(new com.google.gson.Gson().toJson(results)); } catch (Exception e) { System.out.println(e.getMessage()); } } } `;
关键就是这一行:String actualResult_${index} = ${test.replace(/"/g, '\\"')};,通过replace(/"/g, '\\"')把测试用例里的所有双引号替换成Java能识别的转义双引号。
这样处理后,生成的Java代码里测试用例就会变成:
String actualResult_0 = new StringOperations().concatenate("Hello", "world");
引号完美保留,编译也不会报错了,而且用户完全不需要手动加多层转义,和其他语言的输入逻辑保持一致。
备注:内容来源于stack exchange,提问作者Yevhenii Novoseletskyi

