打印给定字符串的所有等效字符串模式,?是可选的

时间:2014-07-09 14:37:55

标签: java algorithm

对于给定的String,可以说abc?de?,abcde,abcd,abde,abd被认为是等效的字符串。 ?之前的字母被视为可选。

我需要编写java代码来为任何给定的字符串打印这样的等效模式。

示例:

输入: ABC?德?

输出: abcde,abcd,abde,abd

输入: ABC?德·F

输出: abcde,abcd,abde,abd,abcdef,abcdf,abdef,abdf

如何编写Java代码来实现此目的?请帮忙。我还没有使用正则表达式。

3 个答案:

答案 0 :(得分:0)

让我总结一下我是如何理解这个问题的:给定一个简化的正则表达式(只有?运算符可用)枚举表达式匹配的所有字符串。

你可以用递归方法解决这个问题:对于第一个问题?在模式中有两种可能性:要么存在之前的字符。两种可能性之后都是与模式的其余部分匹配的所有子字符串。

答案 1 :(得分:0)

我想我明白了:)正如我在评论中发表的那样是我的所作所为:

  1. 解析输入并确定字符是否可选
  2. 创建DFA图表。 DFA包含每个字符的起始节点和节点。边缘由角色标记。但它并不是真正的DFA,因为它没有一套最终状态。 (我注意到它毕竟完成了,所以我的诀窍是在结尾添加一个“#”。图中的所有叶子节点都可以被视为最终节点)
  3. start 节点开始遍历图形。每个访问过的边将其标记的字符添加到字符串中。从开始到叶子的每条路径都是一个完整的字符串。
  4. 以下是abc?de?

    的图表

    Graph for abc?de?

    突出显示字符串abde。你可以看到它有一条从开始到叶子的路径。

    以下是完整的源代码:

    package org.example;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.IdentityHashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    public class SimpleRegEx {
        private static final class InputCharacter {
            final char character;
            final boolean optional;
    
            public InputCharacter(final char character, final boolean optional) {
                this.character = character;
                this.optional = optional;
            }
    
            @Override
            public String toString() {
                return character + (optional ? "?" : "");
            }
        }
    
        private static List<InputCharacter> parseRegEx(String input) {
            input = input + "#";
            final List<InputCharacter> characters = new ArrayList<>();
            for (int i = 0; i < input.length(); i++) {
                final char character = input.charAt(i);
                final boolean eof = (i == input.length() - 1);
                final boolean optional = (!eof && input.charAt(i + 1) == '?');
                final InputCharacter inputCharacter = new InputCharacter(character,
                        optional);
                if (optional) {
                    // Skip ?
                    i++;
                }
                characters.add(inputCharacter);
            }
            return characters;
        }
    
        private static final class Graph {
            final Set<Node> nodes = new HashSet<>();
            final Set<Edge> edges = new HashSet<>();
    
            void dump() {
                System.out.println("{");
                for (final Edge e : edges) {
                    System.out.println("\t" + e.toString());
                }
                System.out.println("}");
            }
        }
    
        private static final class Node {
            final String label;
    
            public Node(String label) {
                this.label = label;
            }
    
            @Override
            public String toString() {
                return "(" + label + ")";
            }
        }
    
        private static final class Edge {
            final Node from;
            final Node to;
            final char label;
    
            public Edge(final Node from, final Node to, final char label) {
                this.from = from;
                this.to = to;
                this.label = label;
            }
    
            @Override
            public String toString() {
                return String.format("(%s)-%s->(%s)", from.label, this.label,
                        to.label);
            }
        }
    
        private static Graph constructGraph(
                final List<InputCharacter> inputCharacters) {
            final Graph graph = new Graph();
    
            final Node start = new Node("start");
            graph.nodes.add(start);
            if (inputCharacters.isEmpty()) {
                return graph;
            }
    
            final Map<InputCharacter, Node> nodes = new IdentityHashMap<>(
                    inputCharacters.size());
    
            // Create a node for every input character
            for (int i = 0, n = inputCharacters.size(); i < n; i++) {
                final Node node = new Node("s" + i);
                nodes.put(inputCharacters.get(i), node);
                graph.nodes.add(node);
            }
    
            // Create an edge to each reachable node
            for (int i = 0, n = inputCharacters.size(); i < n; i++) {
                final InputCharacter fromChar = inputCharacters.get(i);
                final Node fromNode = nodes.get(fromChar);
    
                int j = i + 1;
                while (true) {
                    if (j >= n) {
                        break;
                    }
    
                    final InputCharacter toChar = inputCharacters.get(j);
                    final Node toNode = nodes.get(toChar);
                    final Edge edge = new Edge(fromNode, toNode, toChar.character);
                    graph.edges.add(edge);
    
                    j++;
                    if (j >= n || !toChar.optional) {
                        break;
                    }
                }
            }
    
            // Create an edge from start to all reachable first nodes
            int i = 0;
            do {
                final InputCharacter toChar = inputCharacters.get(i);
                final Node toNode = nodes.get(toChar);
                final Edge edge = new Edge(start, toNode, toChar.character);
                graph.edges.add(edge);
                i++;
                if (i >= inputCharacters.size() || !inputCharacters.get(i).optional) {
                    break;
                }
            } while (true);
    
            return graph;
        }
    
        private static Set<String> computeAllStrings(final Graph graph) {
            // Find start node by name (start node should stored explicity)
            Node start = null;
            for (final Node n : graph.nodes) {
                if ("start".equals(n.label)) {
                    start = n;
                    break;
                }
            }
    
            if (start == null) {
                throw new AssertionError("Expected start node exists");
            }
    
            final Set<String> stringsBefore = traverse(graph, start, "");
            final Set<String> strings = new HashSet<>(stringsBefore.size());
            for (final String s : stringsBefore) {
                // Trim last #
                strings.add(s.substring(0, s.length() - 1));
            }
            return strings;
        }
    
        private static Set<String> traverse(final Graph graph, final Node n,
                final String prefix) {
            final Set<String> strings = new HashSet<>();
            final Set<Edge> outgoingEdges = getAllOutgoingEdges(graph, n);
            final boolean leaf = outgoingEdges.isEmpty();
            if (leaf) {
                strings.add(prefix);
                return strings;
            }
    
            for (final Edge e : outgoingEdges) {
                final String newPrefix = prefix + e.label;
                strings.addAll(traverse(graph, e.to, newPrefix));
            }
            return strings;
        }
    
        private static Set<Edge> getAllOutgoingEdges(final Graph graph, final Node n) {
            final Set<Edge> edges = new HashSet<>();
            for (final Edge e : graph.edges) {
                if (e.from == n) {
                    edges.add(e);
                }
            }
            return edges;
        }
    
        public static void main(String[] args) {
            final String input = "abc?de?";
            final List<InputCharacter> characters = parseRegEx(input);
            System.out.println("Input:");
            System.out.println(characters);
            System.out.println();
    
            final Graph graph = constructGraph(characters);
            System.out.println("Graph:");
            graph.dump();
            System.out.println();
    
            System.out.println("Strings:");
            for (final String s : computeAllStrings(graph)) {
                System.out.println(s);
            }
        }
    }
    

    示例输出:

    Input:
    [a, b, c?, d, e?, #]
    
    Graph:
    {
        (s3)-#->(s5)
        (s1)-c->(s2)
        (s0)-b->(s1)
        (start)-a->(s0)
        (s3)-e->(s4)
        (s1)-d->(s3)
        (s2)-d->(s3)
        (s4)-#->(s5)
    }
    
    Strings:
    abd
    abcd
    abde
    abcde
    

答案 2 :(得分:0)

我有一个更简单的版本。事实证明,图形的构造不是必需的,因为遍历可以通过执行递归函数来隐式完成:

package org.example;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Set;

public class SimpleRegEx {
    private static final class InputCharacter {
        final char character;
        final boolean optional;

        public InputCharacter(final char character, final boolean optional) {
            this.character = character;
            this.optional = optional;
        }

        @Override
        public String toString() {
            return character + (optional ? "?" : "");
        }
    }

    private static List<InputCharacter> parseRegEx(final String input) {
        final List<InputCharacter> characters = new ArrayList<>();
        for (int i = 0; i < input.length(); i++) {
            final char character = input.charAt(i);
            final boolean eof = (i == input.length() - 1);
            final boolean optional = (!eof && input.charAt(i + 1) == '?');
            final InputCharacter inputCharacter = new InputCharacter(character,
                    optional);
            if (optional) {
                // Skip ?
                i++;
            }
            characters.add(inputCharacter);
        }
        return characters;
    }

    private static Set<String> computeAllStrings(
            final List<InputCharacter> characters) {
        if (characters.isEmpty()) {
            return Collections.emptySet();
        }

        final InputCharacter first = characters.get(0);
        final List<InputCharacter> rest = restOfList(characters);
        return step(first, rest);
    }

    private static Set<String> step(final InputCharacter c,
            final List<InputCharacter> rest) {
        final Set<String> strings = new HashSet<>();
        if (rest.isEmpty()) {
            strings.add(String.valueOf(c.character));
            if (c.optional) {
                strings.add("");
            }
            return strings;
        }

        final InputCharacter next = rest.get(0);
        final List<InputCharacter> nextRest = restOfList(rest);
        final Set<String> suffixes = step(next, nextRest);

        for (final String s : suffixes) {
            strings.add(c.character + s);
        }

        if (c.optional) {
            strings.addAll(suffixes);
        }

        return strings;
    }

    private static <T> List<T> restOfList(final List<T> list) {
        if (list.isEmpty()) {
            throw new NoSuchElementException();
        } else if (list.size() == 1) {
            return Collections.emptyList();
        } else {
            return list.subList(1, list.size());
        }
    }

    public static void main(String[] args) {
        final String input = "abc?de?";
        final List<InputCharacter> characters = parseRegEx(input);
        System.out.println("Input:");
        System.out.println(characters);
        System.out.println();

        System.out.println("Strings:");
        for (final String s : computeAllStrings(characters)) {
            System.out.println(s);
        }
    }
}