Java String.matches regex

1

Я пытаюсь посмотреть, отображается ли указанное имя хоста в списке хостов в виде строки с разделителями-запятыми, например:

String list = "aa.com,bb.com,cc.com,dd.net,ee.com,ff.net";
String host1 = "aa.com"; // should be a match
String host2 = "a.com";  // shouldn't be a match
String host3 = "ff.net"  // should be a match

// here is a test for host1     
if (list.matches(".*[,^]" + host1 + "[$,].*")) {
    System.out.println(host1 + " matched");
}
else {
    System.out.println(host1 + " not matched");
}

Но я не подобрался для хоста (aa.com), но тогда я не очень хорошо знаком с регулярным выражением. Пожалуйста, поправьте меня!

BTW Я не хочу использовать решение, в котором вы разделяете список узлов в массиве и затем выполняете соответствующие настройки. Это было слишком медленно, потому что список хостов может быть довольно длинным. Regex apporoach может быть еще хуже, но я пытался заставить его работать в первую очередь.

  • 1
    matches() соответствует всей строке, а не ее части. Вам придется либо разбить строку и сравнить с каждым элементом, либо использовать Pattern ...; Matcher ...; ,
  • 0
    какова схема ввода?
Показать ещё 5 комментариев
Теги:

5 ответов

1
Лучший ответ

Я также думаю, что регулярные выражения слишком медленны, если вы ищете точное соответствие, поэтому я попытался написать метод, который ищет вхождения имени хоста в списке и проверяет каждую подстроку, не является ли она частью более широкого имени хоста (например, "a.com" является частью "aa.com"). Если это не так - результат верен, в списке есть такой хост. Здесь код:

boolean containsHost(String list, String host) {
    boolean result = false;
    int i = -1;
    while((i = list.indexOf(host, i + 1)) >= 0) { // while there is next match
        if ((i == 0 || list.charAt(i - 1) == ',') // beginning of the list or has a comma right before it
                && (i == (list.length() - host.length()) // end of the list 
                || list.charAt(i + host.length()) == ',')) { // or has a comma right after it
            result = true;
            break;
        }
    }
    return result;
}

Но потом я подумал, что будет еще быстрее проверить только 3 случая - совпадения в начале, в середине и в конце списка, которые могут быть выполнены с помощью startsWith, contains и endsWith методов соответственно. Вот второй вариант, который я бы предпочел в вашем случае:

boolean containsHostShort(String list, String host) {
    return list.contains("," + host + ",") || list.startsWith(host + ",") || list.endsWith("," + host);     
}

UPD: комментарий ZouZou к вашему сообщению тоже кажется хорошим, я бы рекомендовал сравнить скорость в списке, подобном имеющимся в реальной ситуации, и выбрать самый быстрый.

  • 1
    Спасибо, Нико. В конце концов я заставил свое регулярное выражение работать, но обнаружил, что он слишком медленный: list.matches ("(. * [,] | ^)" + Str1 + "([,]. * | $)"); (может быть не совсем точно, я написал из моей памяти). В итоге я использовал один и тот же метод (looping, indexOf и проверка границы). Это самый быстрый по сравнению с регулярными выражениями и разделением и сравнением
  • 0
    @kee, ты пробовал второй вариант? Мне все еще кажется, что это быстрее, чем первый.
Показать ещё 1 комментарий
0

Попробуй это:

String list = "aa.com,bb.com,cc.com,dd.net,ee.com,ff.net";
String host1 = "aa.com"; // should be a match
String host2 = "a.com";  // shouldn't be a match
String host3 = "ff.net"  // should be a match 

//For host1
Pattern p1 = Pattern.compile("\\b[A-Za-z]{2}.com");  
Matcher m1 = p1.matcher(list);

if(m1.find()){
   System.out.println(host1 + " matched");
}else{
   System.out.println(host1 + " not matched");
}

//for host2
p1 = Pattern.compile("\\b[A-Za-z]{1}.com");
m1 = p1.matcher(list);

if(m1.find()){
     System.out.println(host2 + " matched");
}else{
     System.out.println(host2+"Not mached");
}

//and so on...

\B означает границу слова (поэтому начало слова в этом случае). [A-Za-z] {n}.com означает символ между AZ или az n раз, за которым следует.com

0

Вы можете использовать лямбда для потока массива и вернуть boolean для соответствия.

String list = "aa.com,bb.com,cc.com,dd.net,ee.com,ff.net";
String host1 = "aa.com"; // should be a match
String host2 = "a.com";  // shouldn't be a match
String host3 = "ff.net";  // should be a match

ArrayList<String> alist = new ArrayList<String>();

for(String item : list.split("\\,"))
{
    alist.add(item);
}

boolean contains_host1 = alist.stream().anyMatch(b -> b.equals(host1));
boolean contains_host2 = alist.stream().anyMatch(b -> b.equals(host2));
boolean contains_host3 = alist.stream().anyMatch(b -> b.equals(host3));

System.out.println(contains_host1);
System.out.println(contains_host2);
System.out.println(contains_host3);

Консольный выход:

true
false
true
0

Как это упоминается в комментариях. Вы не должны использовать Matches, как он пытается соответствовать шаблону регулярного выражения для всей строки, разделенных запятыми. Вы не пытаетесь это сделать. Вы пытаетесь определить, присутствует ли данная подстрока в исходной строке, разделенной запятой.

Для этого вы просто используете имя хоста в методе findall. Однако вы можете просто использовать подстроку, которая не имела бы накладных расходов на компиляцию регулярных выражений.

Регулярные выражения используются для сопоставления строк, которые могут иметь изменения в сопоставленном шаблоне. Никогда не используйте регулярное выражение, если вы хотите выполнить точное сопоставление строк.

0

Это работает префектно, без регулярного выражения

         String list = "aa.com,bb.com,cc.com,dd.net,ee.com,ff.net";
         String host1 = "aa.com"; 
         String host2 = "a.com";  
         String host3 = "ff.net"; 
         boolean checkingFlag=false;
         String [] arrayList=list.split(",");
        System.out.println(arrayList.length);




        for(int i=0;i<arrayList.length;i++)
        {
          // here is a test for host1     
            if (arrayList[i].equalsIgnoreCase(host1))
                checkingFlag=true;

        }

        if (checkingFlag)
            System.out.println("Matched");
        else
            System.out.println("Not matched");

Едва ли принято 20-30 millsecs для выполнения цикла с 1 миллионом записей. В соответствии с вашим комментарием я только что отредактировал. Вы можете проверить это.

long startingTime=System.currentTimeMillis();

        for(int i=0;i<1000000;i++)
        {
            if (i==999999)
                checkingFlag=true;

        }
        long endingTime=System.currentTimeMillis();
        System.out.println("total time in millisecond:"+ (endingTime-startingTime));
  • 0
    правда. Единственная проблема этого подхода в том, что он медленный. Я должен был упомянуть об этом в своем посте, но список хостов может быть несколько сотен (и он меняется), и эту операцию необходимо повторить для более чем 1 млн записей, поэтому я искал более быстрый путь. Может быть, регулярное выражение одинаково медленно, но я хотел, чтобы сначала он работал.
  • 1
    @kee Я сомневаюсь, что хранение огромной строки и выполнение регулярного выражения для определения того, будет ли совпадение хоста, будет быстрее, чем наличие соответствующей структуры данных (такой как HashSet ) для выполнения этой задачи.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню