2017-11-08 1 views
0

나는 String ("abc|a&b")이며 String의 부분을 다른 String으로 바꿉니다. 다음과 같이 교체는 HashMap<String, String>에 저장되어 있습니다 :문자열을 바꾸려면 hashmap 값을 사용하십시오. 오류 발생

  1. "a">"true"
  2. "b">"false"
  3. "abc">"true"

내 결과가 "truefalsec|true&false"입니다,하지만 난 "true|true&false"

필요

내 대구 e :

for(Map.Entry<String, String> entry: map.entrySet()) { 
    if(expression.contains(entry.getKey())) 
     expression = expression.replace(entry.getKey(), entry.getValue()); 
} 
System.out.println(expression); 

의견이 있으십니까?

+2

정렬. – rgettman

+0

당신은 세 가지 대답을 가지고 있습니다. 모두 문제를 해결하지만, 당신은 그 중 하나를 upvote 또는 accept하지 않았습니다! 나는 이전에 내 대답을 받아들이고 댓글을 달았 기 때문에 (당신이 당신의 의견을 삭제 했음에도) 당신이 그들을 본 것을 압니다. 왜? 사람들은 당신을 돕기 위해 진정한 노력을했습니다. –

답변

1

먼저 a 또는 b을 바꾸는 것이 문제입니다. 그런 다음 abc이 남아 있지 않으며 교체되지 않습니다. LinkedHashMap을 사용하고 대체 할 순서대로 요소를 삽입 할 수 있습니다. LinkedHashMap을 사용하면 해당 값을 삽입 한 순서대로 반복 할 수 있으므로 HashMap은 다음과 같은 순서로 값을 반환합니다. 키에 따라 다릅니다 hashCode. > 당신이 필요로 변경하고 문자열을 다시 전체를 병합 -

Map<String, String> map = new LinkedHashMap<>(); 
map.put("abc", "true"); 
map.put("a", "true"); 
map.put("b", "false"); 

for(Map.Entry<String, String> entry: map.entrySet()) { 
    expression = expression.replace(entry.getKey(), entry.getValue()); 
} 
System.out.println(expression); 
1
String expression = "abc|a&b"; 

    Map<String, String> map = new LinkedHashMap<>(); 

    map.put("a", "true"); 
    map.put("abc", "true"); 
    map.put("b", "false"); 

    List<String> parts = Arrays.stream(expression.split("\\W+")).filter(map::containsKey) 
      .map(map::get).collect(Collectors.toList()); 

    Queue<String> separators = new LinkedList<>(Arrays.asList(expression.split("\\w+")) 
      .stream().filter(s -> !s.isEmpty()) 
      .collect(Collectors.toList())); 

    StringBuilder result = new StringBuilder(); 

    for(String part : parts){ 
     result.append(part).append(!separators.isEmpty() ? separators.poll() : ""); 
    } 

    System.out.println(result.toString()); 

당신은 분리에 대한 다음 같은 표현에서 모든 키를 얻을 수 스트림을 사용할 수 있습니다.

1

다음 교체를 위해 스캔을 다시 시작하고 가장 짧은 입력을 먼저 스캔하는 것이 문제입니다. a가 이미 abc에 대한 스캔하기 전에, 다른 무언가로 대체 되었기 때문에 스캔하여

a에 대한 abc 전에, abc과 일치하지 않습니다. 길이가 가장 긴 부분을 스캔 할 부분을 commented by rgettman으로 정렬합니다.

각 입력에 대한 검색을 다시 시작하면 대체 값의 내용을 바꿀 수 있습니다. 예 : 당신이 a 전에 b를 검색 할 경우, bfalse로 대체됩니다,하지만 falseaftruelse로 대체하기 시작 b 결과, true로 대체됩니다.

두 번째 문제점을 수정하고 성능을 향상 시키려면 입력을 한 번만 스캔해야합니다.

입력을 한 번 스캔하고 여러 텍스트 중 하나를 스캔하는 가장 쉬운 방법은 abc|a|b과 같은 정규식을 사용하는 것입니다. 즉 가장 긴 키를 먼저 |으로 구분 한 키를 나열하는 것입니다.

대체 매핑이 무엇이든 할 수 있다고 가정하면 Map에서 동적으로 정규식을 작성해야합니다. 특수 문자는 정규식 특수 문자로 취급되지 않으므로 키와 값을 모두 인용해야한다는 점을 기억해야합니다. 예 일치하는 모든 문자 ..여기

모든 것을 사용 정규식 여분의 반복 수행 (자바 8) 방법 :

public static String replace(String input, Map<String, String> replacementValues) { 
    String regex = replacementValues.keySet().stream() 
        .sorted(Comparator.comparingInt(String::length).reversed() 
            .thenComparing(Function.identity())) 
        .map(Pattern::quote) 
        .collect(Collectors.joining("|")); 
    StringBuffer buf = new StringBuffer(input.length() + 16); 
    Matcher m = Pattern.compile(regex).matcher(input); 
    while (m.find()) 
     m.appendReplacement(buf, Matcher.quoteReplacement(replacementValues.get(m.group()))); 
    return m.appendTail(buf).toString(); 
} 

테스트

Map<String, String> map = new HashMap<>(); 
map.put("a", "true"); 
map.put("b", "false"); 
map.put("abc", "true"); 
System.out.println(replace("abc|a&b", map)); 

출력

true|true&false


스캔이 단어가 아닌 문자열과 일치하는 정규 표현식 컴파일 변경해야하는 경우 : 길이로 감소하는 열쇠는, 그 순서대로 적용

Pattern.compile("\\b(?:" + regex + ")\\b") 
관련 문제