我正在编写一个疯狂的 libs 程序,目的是为了好玩,只是为了编写一些东西。该程序本身非常简单,但由于游戏的性质,我发现自己采用了几个连接,您将用户给定的单词放入一个句子中。是否有一种优雅的解决方法可以减少串联,甚至消除它们以获得更有效的东西?我知道最终是否使用连接没有区别,但我很好奇是否有更优雅的方式来编写这个程序。
更新:我正在使用 java,但如果有一个通用的解决方案来转义连接,那也将不胜感激。
我正在编写一个疯狂的 libs 程序,目的是为了好玩,只是为了编写一些东西。该程序本身非常简单,但由于游戏的性质,我发现自己采用了几个连接,您将用户给定的单词放入一个句子中。是否有一种优雅的解决方法可以减少串联,甚至消除它们以获得更有效的东西?我知道最终是否使用连接没有区别,但我很好奇是否有更优雅的方式来编写这个程序。
更新:我正在使用 java,但如果有一个通用的解决方案来转义连接,那也将不胜感激。
一种解决方案可能是写出整个 mad libs 文件并放入需要替换为所选单词的特殊标记。
你刚买了一个全新的 ${NOUN1},它会变成 ${VERB1} 你。
然后你可以使用例如:String.replace("${NOUN1}", noun1)
for all the words。
您使用哪种语言?
大多数高级语言将具有类似于:
String.Format("{0} {1} {2} {3}", word1, word2, word3, word4);
我可以通过两种方式看到您在游戏中完全避免串联:
将故事模板存储为标记集合:不可变部分和单词占位符。然后循环输出不可变部分和用户单词而不是单词占位符的集合。
编写自定义打印类,该类将使用 charAt 循环遍历模板字符串并输出单词而不是单词占位符。
您可以将单词放在有序数组中并使用 String.format(在 jdk 1.5 或更新版本中)或 jdk 1.4 中的 MessageFormat.format,而不是为每个单词调用 String.replace 或不断附加到 StringBuilder。不幸的是,两者的模式格式不同。
String myPattern = "我的 %s 吃掉了你的 %s"; // 从这里获取用户的值 字符串结果 = String.format(myPattern, (Object[])myArray);
或者
String myPattern = "我的 {0} 吃掉你的 {1}"; // 从这里获取用户的值 字符串结果 = MessageFormat.format(myPattern, (Object[])myArray);
这是一个完整的程序,它使用命令行中的值填充字符串。
公开课形式 { 公共静态无效主要(字符串[] args) { String pattern = "我的 %s 吃掉了你的 %s"; System.out.println(String.format(pattern, (Object[])args)); } }
你的问题有两个方面。
首先,您可能希望避免在代码中直接使用串联。然后,您可以使用运行时中的一些字符串格式化例程。这不会跳过串联,但会将它们从您的代码移动到运行时。
其次,您可能希望更有效地进行连接。那是另一个故事。这里最重要的是为连接的字符串预分配足够大的缓冲区,因为内存重新分配非常昂贵。将子字符串复制到结果字符串中通常成本较低并且是必要的。
就避免串联的一般方法而言,我没有想到任何东西。你可以做的是给自己写一些帮助类来简化你的连接工作。然而,我想给你的一个建议是不要直接将字符串连接为
String x = "Hi";
String y = x + " there!";
字符串连接的实现在 Java 中非常慢,所以最好使用 StringBuffer 代替,特别是如果你做了很多连接:
StringBuffer myStringBuffer = new StringBuffer();
myStringBuffer.append("Hi");
myStringBuffer.append(" there!");
像这样的东西。我现在没有在编译器中检查这个,但我相信你可以自己弄清楚。
不确定Java,但在PHP和Javascript等其他一些语言中,创建数组并连接其所有元素会更快。
Javascript 示例:
var str = str1 + str2 + str3 + "str4" + str5 + "str6" + str7;
var str = [str1, str2, str3, "str4", str5, "str6", str7].join("");
PHP 示例:
$str = $str1 . $str2 . $str3 . "str4" . $str5 . "str6" . $str7;
$str = implode("", array($str1, $str2, $str3, "str4", $str5, "str6", $str7));
如果您想在每个字符串之间放置一个分隔符,这种方法是最好的,在这种情况下,它不仅会更快,而且更紧凑和可读。
通过“避免连接”,我假设您的意思是为新字符串分配空间并分配它?如果您使用的是 .NET,那么我认为StringBuilder应该会有所帮助。
如果您有一个 String 需要经常修改它,那么使用 char[] 数组并在完成修改后创建一个 String 可能会奏效。
如果您愿意,当然可以在不连接的情况下执行此操作。虽然这可能不是很值得。
这部分取决于您要在哪里显示结果。如果它在 Web 或控制台上,那么您可以将结果直接写入输出流。
例如,如果您的模板类似于“%001 跳出 %002”,您可以:
1)扫描字符串以查找变量的位置。2)将字符串分解为组件列表“the”,“jumped out of the”,在这种情况下 3)循环遍历列表中的元素和结果并将它们转储到输出,如下所示:
PrintStream = //get output from somewhere
for(int i = 0; i < pieces.size()-1 ; i++){
ps.print(peices.get(i));
ps.print(answers.get(i));
}
ps.print(pieces.get(pieces.size()-1));//last one
现在。我不知道您是否会称其为“优雅”。它可能会有点快。就像我说的,如果这是一个 Web 服务并且它变得超级流行等,这可能是合适的。
如果这是一个 GUI 应用程序,您可以编写代码来分别绘制字符串,但这可能会比连接花费更多的时间。
但是您可以做的一件事是使用 ByteArrayOutputStream 并预先分配足够的空间,以便它可以包含填充的 madlib 而无需进行额外的分配。那也很快。
为什么要避免连接,如果为了清洁尝试将它排列好,它可能最终看起来非常好。即使你担心性能,你可能不需要使用字符串生成器,我相信如果你做一堆简单的连接(即“fdsfsd”+ var1+var2+“dsfsdf”+“tyhty”它编译成与字符串生成器相同的东西(实际上相同并且看起来更干净)。如果你连接大量的东西,字符串生成器确实有意义在一个循环或复杂的流程中。