当前位置: 首页 > 知识库问答 >
问题:

使用回溯拆分字符串

羊舌涵涤
2023-03-14

我试图编写一个代码,将一个无空格的字符串拆分成有意义的单词,但当我给出“arealways”这样的句子时,它返回['a'、'real'、'ways'],我想要的是['are'、'always'],我的字典包含了所有这些单词。我怎样才能编写一个代码,一直回溯到找到最佳匹配?

返回“a”、“real”、“ways”的代码:

splitter.java:

public class splitter {

    HashMap<String, String> map = new HashMap<>();
    Trie dict;

    public splitter(Trie t) {
        dict = t;
    }

    public String split(String test) {
        if (dict.contains(test)) {
            return (test);
        } else if (map.containsKey(test)) {
            return (map.get(test));
        } else {
            for (int i = 0; i < test.length(); i++) {
                String pre = test.substring(0, i);
                if (dict.contains(pre)) {
                    String end = test.substring(i);
                    String fixedEnd = split(end);
                        if(fixedEnd != null){
                            map.put(test, pre + " " + fixedEnd);
                            return pre + " " + fixedEnd;
                        }else {
                        }
                    
                }
            }

        }
        map.put(test,null);
        return null;
    }
} 

Trie.java:

public class Trie {
    public static class TrieNode {
        private HashMap<Character, TrieNode> charMap = new HashMap<>();
        public char c;
        public boolean endOWord;
        public void insert(String s){
        }
        public boolean contains(String s){
            return true;
        }
    }
    public TrieNode root;
    
    public Trie() {
        root = new TrieNode();
    }
    
    public void insert(String s){
        TrieNode p = root;
        for(char c : s.toCharArray()) {
            if(! p.charMap.containsKey(c)) {
                TrieNode node = new TrieNode();
                node.c = c;
                p.charMap.put(c, node);
            }
            p = p.charMap.get(c);
        }
        p.endOWord = true;
    }
    public boolean contains(String s){
        TrieNode p = root;
        for(char c : s.toCharArray()) {
            if(!p.charMap.containsKey(c)) {
                return false;
            }
            p = p.charMap.get(c);
        }
        return p.endOWord;
    }
    public void insertDictionary(String filename) throws FileNotFoundException{
        File file = new File(filename);
        Scanner sc = new Scanner(file);
        while(sc.hasNextLine())
            insert(sc.nextLine());
    }
    

    public void insertDictionary(File file) throws FileNotFoundException{
        Scanner sc = new Scanner(file);
        while(sc.hasNextLine())
            insert(sc.nextLine());
    }
} 

WordSplitter类:

public class WordSplitter {

    public static void main(String[] args) throws FileNotFoundException {
            
           String test = "arealways";
           String myFile = "/Users/abc/Desktop/dictionary.txt";
           Trie dict = new Trie();
           dict.insertDictionary(myFile);
          splitter sp = new splitter(dict);
          test = sp.split(test);
          
          if(test != null)
          System.out.println(test);
          else
          System.out.println("No Splitting Found.");            
           
    }

        } 

共有1个答案

端木宏才
2023-03-14

使用OP的split方法和Java Baeldung文章中Trie数据结构中的Trie实现,我能够得到以下结果:

realways=real ways
arealways=a real ways

如果我从单词列表(字典)中删除“real”一词,我会得到以下结果:

realways=null
arealways=are always

下面是我用来获得这些结果的全部代码:

public class Splitter {

    private static Map<String, String> map = new HashMap<>();
    private Trie dict;
    
    public Splitter(Trie t) {
        dict = t;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        List<String> words = List.of("a", "always", "are", "area", "real", "ways");
        String test = "arealways";

        Trie t = new Trie();
        for (String word : words) {
            t.insert(word);
        }
        Splitter splitter = new Splitter(t);
        splitter.split(test);
        map.entrySet().forEach(System.out::println);
    }

    public String split(String test) {
        if (dict.find(test)) {
            return (test);
        } else if (map.containsKey(test)) {
            return (map.get(test));
        } else {
            for (int i = 0; i < test.length(); i++) {
                String pre = test.substring(0, i);
                if (dict.find(pre)) {
                    String end = test.substring(i);
                    String fixedEnd = split(end);
                    if (fixedEnd != null) {
                        map.put(test, pre + " " + fixedEnd);
                        return pre + " " + fixedEnd;
                    } else {
                    }

                }
            }

        }
        map.put(test, null);
        return null;
    }

    public static class Trie {
        private TrieNode root = new TrieNode();

        public boolean find(String word) {
            TrieNode current = root;
            for (int i = 0; i < word.length(); i++) {
                char ch = word.charAt(i);
                TrieNode node = current.getChildren().get(ch);
                if (node == null) {
                    return false;
                }
                current = node;
            }
            return current.isEndOfWord();
        }

        public void insert(String word) {
            TrieNode current = root;
            for (char l : word.toCharArray()) {
                current = current.getChildren().computeIfAbsent(l, c -> new TrieNode());
            }
            current.setEndOfWord(true);
        }

        public static class TrieNode {
            private Map<Character, TrieNode> children = new HashMap<>() ;
            private String contents;
            private boolean endOfWord;

            public Map<Character, TrieNode> getChildren() {
                return children;
            }

            public void setEndOfWord(boolean endOfWord) {
                this.endOfWord = endOfWord;
            }

            public boolean isEndOfWord() {
                return endOfWord;
            }
        }

        public void delete(String word) {
            delete(root, word, 0);
        }

        private boolean delete(TrieNode current, String word, int index) {
            if (index == word.length()) {
                if (!current.isEndOfWord()) {
                    return false;
                }
                current.setEndOfWord(false);
                return current.getChildren().isEmpty();
            }
            char ch = word.charAt(index);
            TrieNode node = current.getChildren().get(ch);
            if (node == null) {
                return false;
            }
            
            boolean shouldDeleteCurrentNode = delete(node, word, index + 1) && !node.isEndOfWord();

            if (shouldDeleteCurrentNode) {
                current.getChildren().remove(ch);
                return current.getChildren().isEmpty();
            }
            return false;
        }
    }
}
 类似资料:
  • 如何将过滤器列表拆分为单个过滤器元件?split2String在线程“main”java.util.regex中导致:异常。PatternSyntaxException:索引10或(|和)附近的未闭合组(

  • Java官方文档说明: 例如,字符串使用以下表达式Regex Result生成以下结果: 这就是我需要它工作的方式。然而,如果我运行这个: 它打印: 这与我的预期相去甚远: 为什么会这样?

  • 问题 你想拆分一个字符串。 解决方案 使用 JavaScript 字符串的 split() 方法: "foo bar baz".split " " # => [ 'foo', 'bar', 'baz' ] 讨论 String 的这个 split() 方法是标准的 JavaScript 方法。可以用来基于任何分隔符——包括正则表达式来拆分字符串。这个方法还可以接受第二个参数,用于指定返回的子字符串数

  • eCaused by:org.apache.camel.InvalidPayloadException:没有类型为:org.apache.camel.Exchange的可用正文,但其值为:11484类型为:java.lang.String on:message:11484。原因:没有类型转换器可用于将类型:java.lang.String转换为所需的类型:org.apache.camel.exch

  • 我是 Perl 的新手,但根据我阅读的文档,看起来 Perl 中的 split 函数要求正则表达式模式而不是字符串分隔符作为第一个参数,但我发现使用 之类的东西仍然可以正确拆分字符串。 基于此,我尝试使用可变分隔符(例如。< code>print (split($var,$ string))[0] where < code > $ var = ' ' )并发现它不起作用。我做错了什么? 谢谢! 编

  • 问题内容: 假设有一个字符串… 我想要的就是将字符串拆分为“ my”,“ big”,“ string”等。因此,我尝试 返回java.util.regex.PatternSyntaxException:在索引0附近悬挂元字符’*’ 是正则表达式中的特殊字符,所以我尝试转义…。 同样的例外。我认为有人会知道快速解决方案。谢谢。 问题答案: 和我一起工作。