Apache Commons UrlValidator — настройте, чтобы разрешить символы умлаута

Я хотел бы проверить длинный список строк URL, но некоторые из них содержат символы умлаута, например: ä, à, è, ö и т. д.

Есть ли способ настроить Apache Commons UrlValidator для приема этих символов?

Этот тест не пройден (обратите внимание на ã):

@Test
public void urlValidatorShouldPassWithUmlaut()
{
    // Given
    org.apache.commons.validator.routines.UrlValidator validator;
    validator = new UrlValidator( new String[] { "http", "https" }, UrlValidator.ALLOW_ALL_SCHEMES );

    // When
    String url = "http://dbpedia.org/resource/São_Paulo";

    // Then
    assertThat( validator.isValid( url ), is( true ) );
}

Этот тест пройден (ã заменено на a):

@Test
public void urlValidatorShouldPassWithUmlaut()
{
    // Given
    org.apache.commons.validator.routines.UrlValidator validator;
    validator = new UrlValidator( new String[] { "http", "https" }, UrlValidator.ALLOW_ALL_SCHEMES );

    // When
    String url = "http://dbpedia.org/resource/Sao_Paulo";

    // Then
    assertThat( validator.isValid( url ), is( true ) );
}

Версия программного обеспечения:

<dependency>
    <groupId>commons-validator</groupId>
    <artifactId>commons-validator</artifactId>
    <version>1.4.0</version>
</dependency>

Обновление:

validator.isValid( IDN.toASCII(url) ) также терпит неудачу, поскольку IDN.toASCII(url) делает вещи, которые я еще не понимаю, например. он преобразует http://dbpedia.org/resource/São_Paulo в http://dbpedia.xn--org/resource/so_paulo-w1b, что по-прежнему недействительно в соответствии с UrlValidator


person Alex Averbuch    schedule 10.08.2013    source источник
comment
Вы используете org.apache.commons.validator.routines.UrlValidator или org.apache.commons.validator.UrlValidator?   -  person rahulserver    schedule 10.08.2013
comment
org.apache.commons.validator.routines.UrlValidator (org.apache.commons.validator.UrlValidator устарел)   -  person Alex Averbuch    schedule 10.08.2013
comment
Вы пытались запустить проверку IDN.toASCII(url)?   -  person GGrec    schedule 10.08.2013
comment
спасибо, я только что попробовал, но это не работает, см. комментарий ниже   -  person Alex Averbuch    schedule 10.08.2013
comment
IDN.toAscii(dbpedia.org/resource/São_Paulo) == dbpedia.xn--org/resource/so_paulo-w1b, который по-прежнему недействителен   -  person Alex Averbuch    schedule 10.08.2013
comment
@AlexAverbuch используйте java.net.URLEncoder в качестве моего ответа ниже. Часть умлаута вашего URL должна быть закодирована, чтобы пройти проверку.   -  person rahulserver    schedule 10.08.2013


Ответы (2)


Вы должны закодировать часть умлаута, прежде чем проверять ее как:

import org.apache.commons.validator.routines.UrlValidator;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;

public class UmlautUrlTest {
    public static void main(String[] args) {
        String url = "http://dbpedia.org/resource/";
        String umlautPart="São_Paulo";
        UrlValidator v= null;
        try {
            String s[]={"http", "https"};
            v = new UrlValidator(s, UrlValidator.ALLOW_ALL_SCHEMES);
            String encodedUrl=URLEncoder.encode(umlautPart,"UTF-8");
            System.out.println(v.isValid(url+encodedUrl));
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
    }
}

Результат:

true
S%C3%A3o_Paulo

ИЗМЕНИТЬ:

Вы можете использовать эту функцию для кодирования всего URL-адреса для анализа.

public static String encodeUrl(String url) {
        String temp[] = url.split("://");
        String protocol = temp[0];
        String restOfUrl = temp[1];
        temp = restOfUrl.split("\\.");
        //for the all except last token of host
        for (int i = 0; i < temp.length - 1; i++) {
            try {
                temp[i] = URLEncoder.encode(temp[i], "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
        String temp2[] = temp[temp.length - 1].split("/");
        String host = "";
        for (int i = 0; i < temp.length - 1; i++) {
            host = host + temp[i];
        }
        try {
            host = host + "." + URLEncoder.encode(temp2[0], "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }
        host = host.substring(0);
        String remainingPart = "";
        for (int i = 1; i < temp2.length; i++) {
            try {
                remainingPart = remainingPart + "/" + URLEncoder.encode(temp2[i], "UTF-8");
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
            }
        }
        return (protocol + "://" + host + remainingPart);
    }

И используйте в своем тесте: validator.isValid(encodeUrl(url))

person rahulserver    schedule 10.08.2013
comment
нет ли способа сообщить «UrlValidator» (или альтернативной библиотеке — я открыт для предложений), что умлауты разрешены, а не выполнять кодирование? код должен только проверить, что многие текстовые элементы отформатированы должным образом. преобразование текстовых элементов кажется ненужным и неэффективным, поскольку преобразованный текст немедленно отбрасывается. - person Alex Averbuch; 10.08.2013
comment
@AlexAverbuch способ, которым я дал, является стандартным способом работы со специальными символами в URL-адресах Java. Я не знаю никаких таких специальных библиотек. Мне всегда кажется, что лучше придерживаться более общепринятого способа достижения цели. И, кстати, мое решение не преобразует, а кодирует. - person rahulserver; 10.08.2013
comment
@AlexAverbuch, с чем бы вы ни столкнулись, является открытой проблемой с Apache Commons. См. этот issues.apache.org/jira/browse/ - person rahulserver; 10.08.2013
comment
учитывая ваше решение, что бы я сделал, если бы не знал, в какой части URL-адреса находится умлаут? - person Alex Averbuch; 10.08.2013
comment
спасибо, я также отредактировал, чтобы исправить ошибку, из-за которой он излишне кодировался. персонажи на пути - person Alex Averbuch; 11.08.2013
comment
temp = restOfUrl.split(\\.); Так . символы в имени хоста не кодируются. Где вы редактировали мой код? - person rahulserver; 12.08.2013

При чтении этого вопроса SO (Regex: что такое InCombiningDiacriticalMarks?) я обнаружил, что другим частичным решением является следующее:

    public static boolean removeAccentsAndValidateUrl( String url )
    {
        String normalizedUrl = Normalizer.normalize( url, Normalizer.Form.NFD );
        Pattern accentsPattern = Pattern.compile( "\\p{InCombiningDiacriticalMarks}+" );
        String urlWithoutAccents = accentsPattern.matcher( normalizedUrl ).replaceAll( "" );
        String[] schemes = {"http", "https"};
        long options = UrlValidator.ALLOW_ALL_SCHEMES;
        UrlValidator urlValidator = new UrlValidator( schemes, options );
        return urlValidator.isValid(urlWithoutAccents);
    }

Однако оказывается, что UrlValidator также не работает (среди прочего) с символами "-".

Например, следующее не проходит проверку:

http://dbpedia.org/resource/PENTA_–_Pena_Transportes_Aereos
person Alex Averbuch    schedule 12.08.2013