对于给定的String,可以说abc?de?,abcde,abcd,abde,abd被认为是等效的字符串。 ?
之前的字母被视为可选。
我需要编写java代码来为任何给定的字符串打印这样的等效模式。
示例:
输入: ABC?德?
输出: abcde,abcd,abde,abd
输入: ABC?德·F
输出: abcde,abcd,abde,abd,abcdef,abcdf,abdef,abdf
如何编写Java代码来实现此目的?请帮忙。我还没有使用正则表达式。
答案 0 :(得分:0)
让我总结一下我是如何理解这个问题的:给定一个简化的正则表达式(只有?运算符可用)枚举表达式匹配的所有字符串。
你可以用递归方法解决这个问题:对于第一个问题?在模式中有两种可能性:要么存在之前的字符。两种可能性之后都是与模式的其余部分匹配的所有子字符串。
答案 1 :(得分:0)
我想我明白了:)正如我在评论中发表的那样是我的所作所为:
以下是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);
}
}
}