从查询字符串中过滤参数(使用Guava?)

时间:2011-01-04 16:55:14

标签: java guava

获取此HTTP查询字符串:

foo=fooValue&bar=barValue&phleem=phleemValue

或者这个:

bar=barValue&phleem=phleemValue&foo=someOtherFoo

删除foo参数的最佳方式是什么?

欢迎所有Java解决方案,但是Guava更喜欢。

(没有可用的ServletContext,因此Servlet方法无济于事)

更新:该方法应处理多个要删除的参数。

4 个答案:

答案 0 :(得分:3)

这不是最优雅的解决方案,但可以按预期工作:

private String removeParameter(String string, final String parameterName) {
    List<String> list = newArrayList(string.split("&"));

    Collection<String> filtered = Collections2.filter(list, new Predicate<String>() {
        public boolean apply(String s) {
            return !s.startsWith(parameterName + "=");
        }
    });

    return Joiner.on("&").join(filtered);
}

<强>更新

处理多个参数:

@Test
public void removesMultipleParametersFromQuery() throws Exception {
    String result = removeParameters("foo=fooValue&zee=lalal&bar=barValue&phleem=phleemValue", "foo", "bar");
    assertThat(result, is("zee=lalal&phleem=phleemValue"));
}

private String removeParameters(String query, final String...parameterNames) {
    List<String> list = newArrayList(query.split("&"));
    return Joiner.on("&").join(filter(list, startsWithAnyOf(parameterNames)));
}

private Predicate<String> startsWithAnyOf(final String[] parameterNames) {
    return new Predicate<String>() {
        public boolean apply(String s) {
            return !Iterables.any(newArrayList(parameterNames), isPrefixOf(s));
        }
    };
}

private Predicate<String> isPrefixOf(final String string){
    return new Predicate<String>() {
        public boolean apply(String candidate) {
            return string.startsWith(candidate);
        }
    };
}

答案 1 :(得分:1)

这是我自己的解决方案(但它很丑陋):

public static String removeParameters(final String queryString,
    final String... paramNames){
    Iterable<Predicate<CharSequence>> innerPredicates;
    if(paramNames.length == 0){
        innerPredicates = Collections.emptySet();
    } else{
        innerPredicates =
            Iterables.transform(
            Arrays.asList(paramNames),
                new Function<String, Predicate<CharSequence>>(){

                    @Override
                    public Predicate<CharSequence> apply(
                        final String input){

                        return Predicates.contains(
                            Pattern.compile("^"
                            + Pattern.quote(input) + "=")
                        );
                    }
                });
    }

    final Predicate<CharSequence> predicate =
        Predicates.not(Predicates.or(innerPredicates));
    return Joiner.on("&").join(
        Iterables.filter(Splitter.on('&').split(queryString), predicate));
}

答案 2 :(得分:1)

我想在一端读取查询字符串作为Multimap<String, String>,而在另一端读取查询字符串格式的Multimap<String, String>。然后执行此操作就像为要从查询字符串中删除的每个参数调用removeAll(parameter)一样简单。除了你绝对需要的地方外,不要将它作为原始String处理。

以下是一些代码:

private static final Splitter QUERY_SPLITTER = Splitter.on(CharMatcher.anyOf("&;"));
private static final Joiner QUERY_JOINER = Joiner.on('&');
private static final EntrySplitFunction ENTRY_SPLITTER = 
    new EntrySplitFunction(Splitter.on('='));
private static final EntryJoinFunction ENTRY_JOINER = 
    new EntryJoinFunction(Joiner.on('=').useForNull(""));

public static Multimap<String, String> parseQueryString(String queryString) {
  Multimap<String, String> result = HashMultimap.create();
  Iterable<String> entryStrings = QUERY_SPLITTER.split(queryString);
  for (Map.Entry<String, String> entry : transform(entryStrings, ENTRY_SPLITTER)) {
    result.put(entry.getKey(), entry.getValue());
  }
  return result;
}

public static String toQueryString(Multimap<String, String> multimap) {
  return QUERY_JOINER.join(transform(multimap.entries(), ENTRY_JOINER));
}

private static class EntrySplitFunction 
    implements Function<String, Map.Entry<String, String>> {
  private final Splitter keyValueSplitter;

  private EntrySplitFunction(Splitter keyValueSplitter) {
    this.keyValueSplitter = keyValueSplitter;
  }

  @Override public Map.Entry<String, String> apply(String input) {
    Iterator<String> keyAndValue = keyValueSplitter.split(input).iterator();
    return Maps.immutableEntry(keyAndValue.next(), keyAndValue.next());
  }
}

private static class EntryJoinFunction 
    implements Function<Map.Entry<String, String>, String> {
  private final Joiner keyValueJoiner;

  private EntryJoinFunction(Joiner keyValueJoiner) {
    this.keyValueJoiner = keyValueJoiner;
  }

  @Override public String apply(Map.Entry<String, String> input) {
    return keyValueJoiner.join(input.getKey(), input.getValue());
  }
}

有了这个,你需要做的就是实现你的方法:

public static String removeParameters(String queryString, String... parameters) {
  Multimap<String, String> query = parseQueryString(queryString);
  for (String parameter : parameters) {
    query.removeAll(parameter);
  }
  return toQueryString(query);
}

更好的是,假设您对查询做了其他任何事情,当您达到需要执行此操作的点时,您已经拥有Multimap并且您甚至不愿意编写特殊方法为了它。

答案 3 :(得分:0)

你可以使用番石榴

public static String toQueryString(final Map<String, Object> queryParameters) {
        return "?" + Joiner.on('&').withKeyValueSeparator("=").join(queryParameters);
    }