2

I have a hard coded string that will be used in a URL and I'm wanting to know is what the best way to build this string without having to repeat the words country, or, and, number? This is a shortened version as there are more countries and numbers that will go into the URL.

String url = "&filter=country='UK' or "
                      + "country='FR' or "
                      + "country='CA' or "
                      + "country='US' and "
                      + "number='123' and "
                      + "number='789'";
  • 3
    first of all use `StringBuilder` class, second you can use constants for the keywords if you want to don't repeat them. – Edwin May 24 '17 at 12:41
  • You could also use some well known Java HTTP libs like [Apache HttpClient](http://hc.apache.org/httpcomponents-client-ga/) to build the param string like this tutorial explains http://hc.apache.org/httpcomponents-client-ga/tutorial/html/fundamentals.html#d5e49 – xander May 24 '17 at 13:03

3 Answers3

1

You can use a combination of StringBuilder and String formats to build your specific URL parametrization.

Here's an example:

// test data
List<String> countries = Arrays.asList("UK", "FR","CA", "US");
List<String> numbers = Arrays.asList("123", "789");

// these can be compile-time constants
String disjunct  = " or ";
String conjunct = " and ";
String countryFormat = "country='%s'";
String numberFormat = "number='%s'";

// result 
StringBuilder result = new StringBuilder("&filter=");

// adding countries
for (String country: countries) {
    result.append(String.format(countryFormat, country)).append(disjunct);
}
// removing last "or"
result.delete(result.lastIndexOf(disjunct), result.length());

// adding first "and"
result.append(conjunct);

// adding numbers
for (String number: numbers) {
    result.append(String.format(numberFormat, number)).append(conjunct);
}
// removing last "and"
result.delete(result.lastIndexOf(conjunct), result.length());

// printing result
System.out.println(result);

Output

&filter=country='UK' or country='FR' or country='CA' or country='US' and number='123' and number='789'
Mena
  • 47,782
  • 11
  • 87
  • 106
  • 1
    Why use a foreach loop if you have to remove the last "and"/"or" ? – Michael Markidis May 24 '17 at 12:59
  • @MichaelMarkidis well, you could also use an indexed loop and add a condition for last item in the list to not add the "and/or", but that's exactly as verbose in my opinion. – Mena May 24 '17 at 13:00
0

I suggest that you create arrays to hold each difference, and append them within a for-loop:

String[] countries = {"'UK' or ", "'FR' or ", "'CA' or ", "'US' and "};

String[] numbers = {"'123' and ", "'789'"};

StringBuilder sb = new StringBuilder("&filter=");

for (String country : countries) {
    sb.append("country=").append(country);
}

for (String number : numbers) {
    sb.append("number=").append(number);
}

String url = sb.toString();
Jacob G.
  • 28,856
  • 5
  • 62
  • 116
0

You could also create a helper class that builds the string for you.

public class Test {
private Test() {

    // each country for its own
    IFilterBuilder filterBuilder = new FilterBuilder();
    filterBuilder
            .country("UK").or()
            .country("FR").or()
            .country("CA").or()
            .country("US").and()
            .number(123).and()
            .number(789);

    String myFilter = filterBuilder.getResult();
    System.out.println(myFilter);


    // or a short version with a helper method
    IFilterBuilder smartFilterBuilder = new FilterBuilder();
    smartFilterBuilder.inAnyCountry("UK", "FR", "CA", "US").and().withNumbers(123, 789);

    String result = smartFilterBuilder.getResult();
    System.out.println(result);
}

public static void main(String[] args) {
    new Test();
}

interface IFilterBuilderBinder {
    IFilterBuilder or();
    IFilterBuilder and();
}

interface IFilterBuilder {
    IFilterBuilderBinder country(String countryName);
    IFilterBuilderBinder number(int number);
    String getResult();

    IFilterBuilderBinder inAnyCountry(String... country);
    IFilterBuilderBinder withNumbers(int... numbers);
}

private final static class FilterBuilder implements IFilterBuilder, IFilterBuilderBinder {
    private String filter = "&filter=";

    public IFilterBuilderBinder country(String countryName) {
        filter += "country='" + countryName + "'";
        return this;
    }

    @Override
    public IFilterBuilderBinder number(int number) {
        filter += "number='" + number + "'";
        return this;
    }

    public String getResult() {
        return filter;
    }

    @Override
    public IFilterBuilderBinder inAnyCountry(String... country) {
        for (int i = 0; i < country.length; i++) {
            country( country[i]);
            if(i!=country.length-1){
                or();
            }
        }
        return this;
    }

    @Override
    public IFilterBuilderBinder withNumbers(int... numbers) {
        for (int i = 0; i < numbers.length; i++) {
            number(numbers[i]);
            if(i!=numbers.length-1){
                and();
            }
        }
        return this;
    }

    @Override
    public IFilterBuilder or() {
        filter += " or ";
        return this;
    }

    @Override
    public IFilterBuilder and() {
        filter += " and ";
        return this;
    }
}

}

Phil
  • 306
  • 1
  • 8