用它们的完整形式替换缩写/俚语
Posted
技术标签:
【中文标题】用它们的完整形式替换缩写/俚语【英文标题】:Replacing abbreviations/slangs with their fullforms 【发布时间】:2017-05-31 03:59:45 【问题描述】:我正在使用 HashMap 来存储缩写的完整形式。
public class Test
public static void main(String[] args)
Map<String, String> slangs = new HashMap<String, String>();
slangs.put("lol", "laugh out loud");
slangs.put("r", " are ");
slangs.put("n", " and ");
slangs.put("idk", " I don't know ");
slangs.put("u", " you ");
Set set = slangs.entrySet();
Iterator i = set.iterator();
String sentence = "lol how are you";
StringBuilder sb = new StringBuilder();
for (String word : sentence.split(" "))
while(i.hasNext())
Map.Entry<String, String> me = (Map.Entry)i.next();
if (word.equalsIgnoreCase(me.getKey()))
sb.append(me.getValue());
continue;
sb.append(word);
System.out.println(sb.toString());
输出是:
lollollollaugh out loudlol
这里出了什么问题,我该如何解决?
【问题讨论】:
我知道你为什么让它变得如此复杂。在我的第一个想法中,只需将句子分成单词,然后检查slangs
是否包含它。
你想得到什么结果?
输出应该是:"laugh out how are you"
@Mahn 但我该怎么做呢?
尝试打印所有结果,我不知道你为什么要使用 while(i.hasNext()) 首先,你的句子不起作用,因为你逐字逐句,这意味着例如在大声笑的情况下,在你的句子中你有俚语而不是短语本身。我认为您应该在互联网上查看一些解决方案并获得一些基础。
【参考方案1】:
您不应该遍历条目以找到匹配项,您应该使用 get(Object key)
或 getOrDefault(Object key, V defaultValue)
来获取给定缩写的完整形式,否则而不是获取具有时间复杂度的完整形式在O(1)
中,您将使用O(n)
获得它,这在性能方面当然不好,您将失去将键/值对放在Map
中的真正好处。如果您是因为这种情况而这样做的,只需将您的键仅以小写形式放在您的地图中,然后调用get
或getOrDefault
,并使用小写字母如下:
所以你的循环应该是这样的:
for (String word : sentence.split(" "))
// Get the full form of the value of word in lower case otherwise use
// the word itself
sb.append(slangs.getOrDefault(word.toLowerCase(), String.format(" %s", word)));
输出:
laugh out loud how are you
使用Stream API,它可能只是:
String result = Pattern.compile(" ")
.splitAsStream(sentence)
.map(word -> slangs.getOrDefault(word.toLowerCase(), word))
.collect(Collectors.joining(" "));
【讨论】:
【参考方案2】:不要遍历字典中的键。取而代之的是,只需检查 key 是否在 map 中并获取相应的 value。另外,不要忘记将空格重新添加到组合句子中。
for (String word : sentence.split(" "))
if (slangs.containsKey(word.toLowerCase()))
sb.append(slangs.get(word.toLowerCase()));
else
sb.append(word);
sb.append(" ");
如果您使用的是 Java 8,还可以使用 String.join
、Map.getOrDefault
和 Streams:
String s = String.join(" ", Stream.of(sentence.split(" "))
.map(word -> slangs.getOrDefault(word.toLowerCase(), word))
.toArray(n -> new String[n]));
后一种方法还有一个好处是不会在句子的第一个单词之前或最后一个单词之后添加空格。
【讨论】:
您应该使用word.toLowerCase()
进行查找。此外,您可以使用String[]::new
代替n -> new String[n]
。
@shmosel 同意这两点。奇怪的是,String[]::new
在 Eclipse 中给了我奇怪的编译问题,所以无法测试,只更改了第一个。【参考方案3】:
简单地说,我想你只需要检查slangs
是否包含这个关键字。
请检查我的代码。
public class Test
public static void main(String[] args)
Map<String, String> slangs = new HashMap<String, String>();
slangs.put("lol", "laugh out loud");
slangs.put("r", " are ");
slangs.put("n", " and ");
slangs.put("idk", " I don't know ");
slangs.put("u", " you ");
String sentence = "lol how are you";
String[] words = sentence.split(" ");
for (String word : words)
String normalizeWord = word.trim().toLowerCase();
if(slangs.containsKey(normalizeWord))
sentence = sentence.replace(word, slangs.get(normalizeWord));
System.out.println(sentence);
【讨论】:
如果您要调用get()
,containsKey()
是多余的。 replaceAll()
可能会在正则表达式特殊字符上失败。如果您要使用replaceAll()
,则迭代单词而不是条目似乎有点倒退。
@shmosel - 实际上我发现使用 containsKey + 比直接获取变量更容易阅读,测试 var 是否为空,然后使用。是的,效率稍低,但不应该引起注意。我同意迭代顺序;这是一个更多更明显的低效率
@shmosel 感谢您的评论。同意因为循环语句,我们应该使用replace
。将更新我的答案。我想如果不使用containsKey()
,我们需要使用一些像StringBuilder这样的临时变量来获得正确的答案。以上是关于用它们的完整形式替换缩写/俚语的主要内容,如果未能解决你的问题,请参考以下文章