简体   繁体   中英

How can I get a string between 2 asterisks?

So I was looking at reddit and was wondering how they managed to do the formatting thing with the bold and the italic via asterisks encapsulating text, so I tried replicating that effect in java. I tried a lot of things and the following code is a scramble/mix/mashup of everything I tried

  public static ArrayList<String> redditReformat(String message) {
    ArrayList<String> single = new ArrayList<>();
    ArrayList<String> doubl = new ArrayList<>();
    ArrayList<String> fin = new ArrayList<>();

    if (message.contains("*") && !message.contains("**")) {
        ArrayList<Integer> asterisks = new ArrayList<>();

        for (int index = message.indexOf("*"); index >= 0; index = message.indexOf("*", index + 1)) {
            asterisks.add(index);
        }

        HashMap<Integer, Integer> patterns = new HashMap<>();
        for (int start : asterisks) {
            for (int end : asterisks) {
                if (start < end) {
                    if ((start + 1) != end) {
                        if (!patterns.containsKey(start) && !patterns.containsValue(end)) {
                            single.add(message.substring(start, end));
                            patterns.put(start, end);
                        }
                    } else {
                        if (message.charAt(start + 1) == message.charAt(start)) {
                            if (message.charAt(end + 1) == message.charAt(end)) {

                                ArrayList<Integer> doubleasterisks = new ArrayList<>();

                                if (!patterns.containsKey(start) && !patterns.containsValue(end)) {
                                    doubl.add(message.substring(start + 2, end - 1));
                                    if (doubleasterisks.size() < 2) {
                                        doubleasterisks.add(start + end);
                                    } else {
                                        patterns.put(doubleasterisks.get(1), doubleasterisks.get(2));
                                        doubleasterisks.clear();
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    for (String s : single) {
        fin.add(s);
    }
    for (String d : doubl) {
        fin.add(d);
    }
    return fin;
}

Yes it's messy and probably horrible, I've tried simple and complex things but this isn't going well. The method is supposed to return the asterisks between the a message as well, so like "haha *lol* potato" (stackoverflow formats the asterisks)

It currently returns "*lol" instead of "*lol*" and it just doesn't work when done with **

It also fails when there's more than one encapsulation.

You can use a regular expression pattern to find occurrences:

String s = "blah *lol* blah";
Pattern pattern = Pattern.compile("\\*([^\\*]*)\\*");
Matcher matcher = pattern.matcher(s);
while (matcher.find()) {
    System.out.println(matcher.group(1));
}

Prints:

lol

If you haven't come across regular expressions before, I strongly recommend you learn about them. They are useful in lots of text-extraction / text-munging situations.

The expression:

\\*([^\\*]*)\\*

Breaks down as follows:

\\*      match an asterisk (it's escaped with a backslash
         because * is a meaningful character in a regular 
         expression. It has to be double escaped because
         backslash is a meaningful character in a Java
         string.

(        start a capturing group

[^\\*]*  match zero or more characters that are not asterisk

)        end the capturing group

\\*      match another asterisk              

(Actually, regular expressions may not handle every case perfectly here, as they don't handle nesting, eg *italic **bold*** , but are probably good enough. A "proper" solution would be to write some lexing/parsing code that takes each character at a time, and maintains state. For this situation you may even need backtracking, as it's not clear whether a *** starts an italic or bold section until you have parsed further.)

If you want this functionality, there are lots of pre-written Markdown parsers.

Updated to use Bukkit's ChatColor constants 更新为使用Bukkit的ChatColor常量

As people in the comments are saying you should probably use regular expressions for this task.

Reading a bit about Minecraft chat formatting it seems that in order to make text bold you need to surround it like this: §ltext§r . For underline it is similar: §ntext§r . In order to include the special character in the Java code you can use the unicode .

Here is some example code using regular expressions to replace single asterisks as underline and double asterisks as bold:

public static String applyFormatting(String message) {
  // BOLD: replace all occurrences of "**text**" with BOLD+"text"+RESET
  message = message.replaceAll("\\*\\*([^\\*]*)\\*\\*", ChatColor.BOLD + "$1" + ChatColor.RESET);
  // UNDERLINE: replace all occurrences of "*text*" with ITALIC+"text"+RESET
  message = message.replaceAll("\\*([^\\*]*)\\*", ChatColor.ITALIC + "$1" + ChatColor.RESET);
  return message;
}

This will not work with nested formatting like **This *is* a test** though.
It has not been tested with Minecraft.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM