【问题标题】:Is there a way to keep the upper and lower case writing of words when searching for anagrams?搜索字谜时,有没有办法保持单词的大写和小写?
【发布时间】:2020-02-20 10:33:35
【问题描述】:

我需要编写一个程序,将整个文本文件读入字符串并在其中搜索字谜。输出必须是同一类型的所有字谜,位于单独的行中,并带有原始的大写和小写字母。

我尝试了以下方法,但没有给我想要的结果(显然都是小写):

String input = inputStringBuilder.toString();
input = input.replaceAll("[^äÄöÖüÜßa-zA-Z ]", "").toLowerCase();
String[] sentence = input.split(" ");

Map<String, Set<String>> anagrams = new HashMap<>();

for(int i = 0; i < sentence.length; i++){

        char[] charwords = sentence[i].toCharArray();

        Arrays.sort(charwords);

        String key = new String(charwords);

        Set<String> anagramSet = anagrams.get(key);
        if (anagramSet == null) {
          anagramSet = new HashSet<>();
          anagrams.put(key, anagramSet);
        }

   anagramSet.add(sentence[i]);

}

【问题讨论】:

  • 你明白什么是字谜吗?我在代码中没有看到您甚至尝试检查字谜的任何地方。
  • @MushifAliNawaz 是的,我知道它的作用。这就是我的问题。如果我删除它,整个事情就不再起作用了(因为大小写字符不一样)
  • .toLowerCase()input 语句移动到 charwords 语句:char[] charwords = sentence[i].toLowerCase().toCharArray(); --- 您想要键入无大小写(在 sort() 之前),但是sentence 数组中的单词具有原始大小写。
  • @Andreas 这行得通,但它保留了重复项(当然不是字谜)
  • 什么重复?您存储在 MapSet 中,两者都不允许重复。

标签: java anagram


【解决方案1】:

首先您需要移动toLowerCase() 呼叫。

input = input.replaceAll("[^äÄöÖüÜßa-zA-Z ]", ""); // <== Removed from here
String[] sentence = input.split(" ");

Map<String, Set<String>> anagrams = new HashMap<>();

for(int i = 0; i < sentence.length; i++){

        char[] charwords = sentence[i].toLowerCase().toCharArray(); // <== Added here

        Arrays.sort(charwords);

        String key = new String(charwords);

        Set<String> anagramSet = anagrams.get(key);
        if (anagramSet == null) {
          anagramSet = new HashSet<>();
          anagrams.put(key, anagramSet);
        }

   anagramSet.add(sentence[i]);

}

接下来,您需要从 anagrams 映射中删除不包含任何实际字谜的条目。

问题代码中完全缺少此步骤,其中大小为 1 的 Set 的映射条目不是实际的字谜。

既然Set 包含带有原始大小写的单词,则可能存在像"The""the" 这样的非字谜,并且也必须消除,假设没有真正的字谜.如果有真正的字谜,则应保留各种大小写变体。

要检查这一点,请将所有单词添加到小写集合,如果这个新集合的大小为 1,则消除,否则保留大小写保留集合。

// code from above here
for (Iterator<Set<String>> iter = anagrams.values().iterator(); iter.hasNext(); ) {
    Set<String> words = iter.next();
    if (words.size() == 1) {
        iter.remove(); // Not anagram: Single spelling only
    } else {
        Set<String> lower = new HashSet<>();
        for (String word : words)
            lower.add(word.toLowerCase());
        if (lower.size() == 1) {
            iter.remove(); // Not anagram: Multiple case variants, but all same spelling
        }
    }
}

测试

Input:  This is a test of 'the' and 'The'
Result: {}

Input:  This is a test of 'the', 'The', and 'eth'
Result: {eht=[the, The, eth]}

如果您不想保留同一单词的所有大小写变体,则只需使用new TreeSet&lt;&gt;(String.CASE_INSENSITIVE_ORDER)使集合不区分大小写

(代码精简,部分使用 Java 8 特性)

Map<String, Set<String>> anagrams = new HashMap<>();
for (String word : input.replaceAll("[^äÄöÖüÜßa-zA-Z ]", "").split(" ")) {
    char[] letters = word.toLowerCase().toCharArray();
    Arrays.sort(letters);
    String key = new String(letters);
    anagrams.computeIfAbsent(key, k -> new TreeSet<>(String.CASE_INSENSITIVE_ORDER))
            .add(word);
}
anagrams.values().removeIf(words -> words.size() == 1);

测试

Input:  This is a test of 'the' and 'The'
Result: {}

Input:  This is a test of 'the', 'The', and 'eth'
Result: {eht=[eth, the]}

Input:  This is a test of 'The', 'the', and 'eth'
Result: {eht=[eth, The]}

【讨论】:

    猜你喜欢
    • 2021-04-01
    • 2021-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-27
    • 2020-05-14
    • 2010-12-28
    • 2018-05-27
    相关资源
    最近更新 更多