【问题标题】:Java string problem: replacing specific part of a stringJava字符串问题:替换字符串的特定部分
【发布时间】:2020-08-11 18:38:41
【问题描述】:

方法replacement 替换[Name] 或{Name} 括号中的所有名称(来自给定的字符串a),如果[] 这些括号替换为电话号码,或者如果{} 这些括号替换为电子邮件.通讯录用数组tel表示,其元素可以是“Tel NametelephoneNumber”或“Mail Name mail”。例如,如果输入是:“您可以通过电话号码 [Jake] 或电子邮件 {Jake} 联系 jake”,则输出应为“您可以通过电话号码 +12345 或电子邮件 jake@gmail.com 联系 jake”,并且 tel 元素是“Tel Jake +12345”和“Mail Jake jake@gmail.com”。如果地址簿中不存在给定的名称,则对字符串不执行任何操作。我遇到的问题是在替换子字符串时我使用方法replaceFirst,它将替换我要替换的子字符串的第一次出现。

也许更简短的问题是如何替换字符串的特定部分?

public static String replacement(String a, String[] tel) {

    for (int i = 0; i<a.length()-1; i++) {
        char c = a.charAt(i);
        if (c=='[') {
            int ind = a.indexOf(']', i);
            String name = a.substring(i+1, ind);
            for (int j=0; j<tel.length; j++) {
                int ind1 = tel[j].indexOf(' ', 4);
                String name1 = tel[j].substring(4, ind1);
                String p = tel[j].substring(0,3);
                String help = "Tel";
                int temp = p.compareTo(help);
                if (ime.equals(ime1)==true && temp==0) {
                    String telephone = tel[j].substring(ind1+1, tel[j].length());
                    a = a.replaceFirst(name, telephone);
                } 
            } 
        }
        if (c=='{') {
            int ind = a.indexOf('}', i);
            String name = a.substring(i+1, ind);
            for (int j=0; j<tel.length; j++) {
                int ind1 = tel[j].indexOf(' ', 5);
                String name1 = tel[j].substring(5, ind1);
                String p = tel[j].substring(0,4); 
                if (name.equals(name1) && p.compareTo("Mail")==0) {
                    String mail = tel[j].substring(ind1+1, tel[j].length());
                    
                    a = a.replaceFirst(name, mail);

                }
            }
        }
    }
    return a;
}

主要:

String a = "In NY you can contact peter via telephone number [Peter] or e-mail {Peter}. In London you can contact anna via telephone number [Anna] or e-mail {Anna}."
            + "In Chicago you can contact shawn via telephone number [Shawn] or e-mail {Shawn}";
String [] tel = {"Mail Peter peter@gmail.com", "Tel Anna +3456","Tel Shawn +1234", "Mail Shawn shawn@yahoo.com"};
String t = replacement(a,tel);
System.out.println(t);

控制台:

In NY you can contact peter via telephone number [peter@gmail.com] or e-mail {peter@gmail.com}.
In London you can contact anna via telephone number [+3456] or e-mail {Anna}.In Chicago you can 
contact shawn via telephone number [+1234] or e-mail {shawn@yahoo.com}

【问题讨论】:

    标签: java string


    【解决方案1】:

    我不会将数据类型(电子邮件与电话号码)和替换键编码为字符串,而是将数据放入单独的变量中,并使用 Map 之类的数据结构:

    Map<String, String> tel = Map.of("Anna", "+3456", "Shawn", "+1234");
    Map<String, String> mail = Map.of("Peter", "peter@gmail.com", "Shawn", "shawn@yahoo.com");
    String t = replacement(a, tel, mail);
    

    replacement 函数可以使用 正则表达式 来查找与要替换 [something]{something} 的关键字匹配的子字符串。它会检查它找到的是哪一个,并使用它在地图数据结构中找到的电话或电子邮件添加一个替换。

    private static String replacement(String a, Map<String, String> tel, Map<String, String> mail) {
        Pattern compile = Pattern.compile("\\{(.*?)\\}|\\[(.*?)\\]");
        Matcher matcher = compile.matcher(a);
        StringBuilder sb = new StringBuilder();
    
        // Find substrings matching {something} and [something]
        while (matcher.find()) {
            String matched = matcher.group(0);
    
            // Which was it, { or [ ?
            if (matched.charAt(0) == '{') {
                // Email. Replace from "mail"
                String emailAddress = mail.getOrDefault(matcher.group(1), matched);
                matcher.appendReplacement(sb, emailAddress);
            } else if (matched.charAt(0) == '[') {
                // Telephone. Replace from "tel"
                String phoneNumber = tel.getOrDefault(matcher.group(2), matched);
                matcher.appendReplacement(sb, phoneNumber);
            }
        }
        matcher.appendTail(sb);
        return sb.toString();
    }
    

    【讨论】:

      【解决方案2】:

      处理指定格式的字符串最好使用regular expressions。您定义一个指定的模式,在找到与您的模式匹配的部分后,您可以替换它或进一步分析。

      最好编写代码以使其易于扩展。例如 - 如果添加了一个新的联系表格(家庭地址、传真、公司电话号码),它应该很容易在代码中处理。您的解决方案使解决此类问题变得更加困难,因为需要一个全新的if 分支,而且很容易出错,这也会降低代码的可读性。

      在处理某种字典时(例如您的输入字符串数组),值得使用Map,因为它使处理速度更快并且代码更具可读性。当存在常量值时,也值得将它们定义为常量或枚举值。此外 - Java 允许编写更实用、更易读的函数式代码,而不是嵌套的 for-eaches - 值得使用这些功能 (JDK8+)。

      请在下面找到代码 sn-p 和 a whole project with tests comparing your solution to mine on GitHub - 您可以在那里查看或克隆存储库并自行验证代码:

      // we can simply add new contact types and their matchers using the constant below
      private static final Map<Pattern, ContactType> CONTACT_PATTERNS = Map.of(
              Pattern.compile("\\[(\\S+)]"), ContactType.TEL,
              Pattern.compile("\\{(\\S+)}"), ContactType.MAIL
      );
      
      @Override
      public String replace(String input, String[] dictionary) {
          // we're mapping the dictionary to make it easier to use and more readable (also in debugging)
          Map<ContactType, Map<String, String>> contactTypeToNameToValue =
                  Arrays.stream(dictionary)
                        .map(entry -> entry.split(" ")) // dictionary entry is split by ' ' character
                        .collect(groupingBy(entry -> ContactType.fromString(entry[0]), // first split part is the contact type
                                            toMap(entry -> entry[1], // second part is the person's name
                                                  entry -> entry[2]))); // third part is the contact value
          String output = input;
          for (Map.Entry<Pattern, ContactType> entry : CONTACT_PATTERNS.entrySet()) {
              Pattern pattern = entry.getKey();
              ContactType contactType = entry.getValue();
              output = pattern.matcher(output)
                              .replaceAll(matchResult -> {
                                  String name = matchResult.group(1);
                                  // we search our dictionary and get value from it or get the original value if nothing matches given name
                                  return Optional.ofNullable(contactTypeToNameToValue.get(contactType))
                                                 .map(nameToValue -> nameToValue.get(name))
                                                 .orElseGet(matchResult::group);
                              });
          }
          return output;
      }
      
      public enum ContactType {
          TEL,
          MAIL;
      
          private static ContactType fromString(String value) {
              return Arrays.stream(values())
                           .filter(enumValue -> enumValue.name().equalsIgnoreCase(value))
                           .findFirst()
                           .orElseThrow(RuntimeException::new);
          }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-16
        • 2020-10-12
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多