简体   繁体   中英

How to print not match string

I would like to print not matching string but the result null.

public class Replacement  {
   public static void main(String[] ignored)  {

      String str = "aaa bbb ddd";
      Map<String, String> mapping = new HashMap<>();
      mapping.put("aaa", "hello");
      mapping.put("bbb", "java");
      mapping.put("ccc", "world");

      Pattern pattern = Pattern.compile("([a-zA-Z_]+)"); // pattern compiling
      Matcher matcher = pattern.matcher(str); // pattern matching

      StringBuffer sb = new StringBuffer();
      while(matcher.find())  { // while matcher found
         String replace = mapping.get(matcher.group());
         matcher.appendReplacement(sb, replace + " ");
      }
      matcher.appendTail(sb);

      System.out.println(sb);
  }
}

The result:

hello java null // I expected "hello java dddd

Do I need to put while(!matcher.find())

To achieve what you want, you need to check whether a replacement exists or not, if replacement does not exist then you need to append the key itself

     String replace = mapping.get(matcher.group());
     if(replace==null) {
         replace = matcher.group();
     }
     matcher.appendReplacement(sb, replace + " ");

hope this helps.

The following code has been tested on IntelliJ 11 and appears to be working correctly. I think your intention is to match each string in the str input, and potentially replace it, if it has a mapping in the hash map. The problem is that you are doing a replace without actually checking if a matched word appears in the map. I added logic that conditionally makes a replacement iff a match has a mapping.

public class Replacement  {
    public static void main(String[] ignored)  {

        String str = "aaa bbb ddd";
        Map<String, String> mapping = new HashMap<String, String>();
        mapping.put("aaa", "hello");
        mapping.put("bbb", "java");
        mapping.put("ccc", "world");

        Pattern pattern = Pattern.compile("([a-zA-Z_]+)");compiling
        Matcher matcher = pattern.matcher(str);

        StringBuffer sb = new StringBuffer();
        while(matcher.find())  {
            String key = matcher.group();       // matched word is key into the map
            String value = mapping.get(key);    // attempt to get mapped word
            if (value != null) {                // if mapping exists,
                str = str.replace(key, value);  //   then make replacement
            }
        }
        System.out.println(str);
    }
}

Update:

If you need to worry about edge cases along the lines of what @ajb pointed out, it would be safer to just split your original string by space, selectively replace each word, and then roll it back up into a single string again:

String[] parts = str.split(" ");
String output = "";

for (int i=0; i < parts.length; ++i) {
    String value = mapping.get(parts[i]);
    if (value == null) {
        value = parts[i];
    }

    if (i > 0) {
        output += " ";
    }
    output += value;
}

If there is no match in the map, mapping.get() would return null in this code:

     String replace = mapping.get(matcher.group());
     matcher.appendReplacement(sb, replace + " ");

I'm not sure what you expected. It seems like you thought that if the string wasn't in the map, the code would magically know that you would want to skip the appendReplacement . But, of course, code can't read minds and doesn't work magically. If replace is null , the program would still go ahead and try to execute the next line.

The result you're seeing is because of how the + operator works on strings; if one of the operands is null , then + actually puts the four-character string "null" into the result. Thus, replace + " " is "null " , and the code replaces your unmatched string with that. (However, this:

matcher.appendReplacement(sb, replace);

would have given you a NullPointerException.)

So basically, you want to tell it not to do the replacement if there's no match, and there are a couple ways to do this:

 String replace = mapping.get(matcher.group());
 if (replace != null) {
     matcher.appendReplacement(sb, replace + " ");
 }

or

if (mapping.containsKey(matcher.group())) {
    String replace = mapping.get(matcher.group());
    matcher.appendReplacement(sb, replace + " ");
}

Because of the way appendReplacement works, if you skip it for one matcher.find() , it doesn't touch matcher 's append position . So the next time through the loop, if there is a match, the previous match (that didn't have a mapping) would get copied in at that point. Or, if we fall out of the loop, the previous match would get copied by appendTail .

But note that the code you wrote is inserting extra spaces into the result. If that's what you want, then you might want to fix the replacement so that it adds an extra space even if there's no mapping, instead of just copying it in the next append .

 String replace = mapping.get(matcher.group());
 if (replace == null) {
     replace = matcher.group();
 }
 matcher.appendReplacement(sb, replace + " ");

which would in effect replace "ddd" by "ddd " in your example. You'll have to decide how you want to handle the spaces. Maybe you really didn't want extra spaces? Remember that the append methods will copy text from the input up to the point that matched, including those space characters. So you really don't need to include an extra space, unless you really want to increase the number of spaces in the result.

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