Java частичное совпадение строк

Частичное совпадение строк в случае List.contains (String)

если я сделаю list.contains(«EFGH») , он возвращается true . Могу ли я получить истину в случае list.contains(«IJ») ? Я имею в виду, могу ли я частично сопоставить строки, чтобы узнать, существуют ли они в списке? У меня список из 15000 строк. И мне нужно проверить около 10000 строк, есть ли они в списке. Что может быть другим (более быстрым) способом сделать это? Благодарю.

«Могу я получить true в случае list.contains(«IJ») ?» Что случилось, когда ты пытался Это? — Andrew Thompson

ты должен знать какой именно термин, который он соответствует, или достаточно знать, что он соответствует одному из ваших терминов (не зная, какой из них)? — Bohemian♦

9 ответы

  • Временная сложность табличного алгоритма O (n), время предварительной обработки
  • Временная сложность алгоритма поиска O (k)

Итак, сложность всего алгоритма составляет O (n + k).

Обычный брут-форс будет иметь временную сложность O (нм)

Более того, алгоритм KMP будет иметь такую ​​же сложность O (k) для поиска с той же строкой поиска, с другой стороны, это всегда будет O (km) для подхода грубой силы.

Что такое m в O (нм) и O (км)? Также ознакомьтесь с моим простым решением O (k) ниже. Почему это не сработает? — Райан Шиллингтон

Возможно, вы хотите поместить каждую группу String в HashSet, и под фрагментом я имею в виду не добавлять «IJ KL», а добавлять «IJ» и «KL» отдельно. Если вам нужны как список, так и возможности поиска, вам может потребоваться поддерживать две коллекции.

В качестве второго ответа, перечитав свой вопрос, вы также можете унаследовать от интерфейса List , специализируемся на Strings только и переопределить метод contains ().

public class PartialStringList extends ArrayList  < public boolean contains(Object o) < if(!(o instanceof String)) < return false; >String s = (String)o; Iterator iter = iterator(); while(iter.hasNext()) < String iStr = iter.next(); if (iStr.contain(s)) < return true; >> return false; > > 

Судя по вашим предыдущим комментариям, возможно, это не та скорость, которую вы ищете, но больше ли она похожа на то, о чем вы просили?

List list = new ArrayList(); list.add("ABCD"); list.add("EFGH"); list.add("IJ KL"); list.add("M NOP"); list.add("UVW X"); boolean hasString = IterableUtils.contains(list, "IJ", new Equator() < @Override public boolean equate(String o1, String o2) < return o2.contains(o1); >@Override public int hash(String o) < return o.hashCode(); >>); System.out.println(hasString); // true 

Вы можете перебирать список, а затем вызывать contains () для каждой строки.

public boolean listContainsString(List list. String checkStr) < Iteratoriter = list.iterator(); while(iter.hasNext()) < String s = iter.next(); if (s.contain(checkStr)) < return true; >> return false; > 

Думаю, что-то подобное должно сработать.

Вот чем я сейчас занимаюсь. Но это даст мне ложь, если я хочу частично соответствовать. Также при этом мне придется перебрать 15000 записей 10000 раз. — y2p

Тогда я не уверен, что понимаю вопрос. Я почти уверен, что это вернет истину при частичном совпадении, как вы и просили, хотя здесь уже поздно, поэтому я, возможно, полностью упускаю ошибку в усталости. Кроме того, как предлагает судно на воздушной подушке, знаете ли вы, будут ли они так или иначе разделены (пробелом или другим символом)? Если так, то проблема будет проще. — Roadrunner-EX

java.util.List list = new java.util.ArrayList(); list.add("ABCD"); list.add("EFGH"); list.add("IJ KL"); list.add("M NOP"); list.add("UVW X"); java.util.regex.Pattern p = java.util.regex.Pattern.compile("IJ"); java.util.regex.Matcher m = p.matcher(""); for(String s : list)

Вот код, который использует регулярное выражение для сокращения внутреннего цикла, если никто тестовых строк находятся в целевой строке.

public static void main(String[] args) throws Exception < Listhaystack = Arrays.asList(new String[] < "ABCD", "EFGH", "IJ KL", "M NOP", "UVW X" >); List needles = Arrays.asList(new String[] < "IJ", "NOP" >); // To cut down on iterations, create one big regex to check the whole haystack StringBuilder sb = new StringBuilder(); sb.append(".*("); for (String needle : needles) < sb.append(needle).append('|'); >sb.replace(sb.length() - 1, sb.length(), ").*"); String regex = sb.toString(); for (String target : haystack) < if (!target.matches(regex)) < System.out.println("Skipping " + target); continue; >for (String needle : needles) < if (target.contains(needle)) < System.out.println(target + " contains " + needle); >> > > 
Skipping ABCD Skipping EFGH IJ KL contains IJ M NOP contains NOP Skipping UVW X 

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

Читайте также:  Image with url html code

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

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

Источник

Как я могу выполнить частичное совпадение с java.util.regex. *?

Я использую классы java.util.regex. * для регулярного выражения в Java и все до сих пор хорошо. Но сегодня у меня другое требование. Например, рассмотрим шаблон как «абаб». Теперь, если входной String является aa, он определенно не будет соответствовать, однако есть еще вероятность, что если я добавлю bb, он станет aabb, и он будет соответствовать. Однако, если бы я начал с cc, независимо от того, что я добавляю, он никогда не будет соответствовать. Я изучил класс Pattern и Matcher, но не нашел способа добиться этого. Вход будет поступать от пользователя, и система должна ждать, пока шаблон не будет соответствовать, или он никогда не будет соответствовать независимо от ввода. Любая подсказка? Спасибо.

Так что, чтобы понять это прямо — вы хотите, так сказать, «продолжить регулярное выражение» с того момента, на котором вы остановились (без повторного выражения регулярного выражения для всей строки), на основе дополнительного пользовательского ввода? Если это так, это невозможно, по причинам, которые я могу объяснить, если вы подтвердите это — если вы не укажете дополнительные ограничения.

Спасибо, ребята, что ответили. По сути, я хочу знать, что строка, которую я пытаюсь сопоставить, все еще имеет возможность сопоставления с шаблоном с последующим вводом, или она никогда не будет совпадать вообще. У моего паттерна могут быть только Range [], Sub Range [-], * и Digits (/ d) и альфа A, B, C, D. В основном любая комбинация DTMF с клавиатуры набора номера.

Можете ли вы привести нам пример регулярного выражения, которое вы планируете использовать? Большинство ответов ниже требуют большой работы, если вы хотите их реализовать, но, возможно, в вашей реальной ситуации есть более простой способ.

@amit, так что вы хотите знать, может ли в текущем состоянии ввода быть добавлен какой-либо дополнительный ввод, чтобы регулярное выражение было выполнено?

Читайте также:  Javascript encodeuricomponent in php

Между прочим, я ухожу на день, начинающийся сейчас, но если вы можете ответить на мой комментарий, когда я вернусь, я дам вам ответ A +;)

@incrediman: Интересно, что вы скажете, когда завтра вернетесь на работу и прочитаете ответ Алана Мура 🙂

7 ответов

Вам следовало бы более внимательно изучить API-интерфейс Matcher; hitEnd() работает точно так, как вы описали:

import java.util.regex.*; public class Test < public static void main(String[] args) throws Exception < String[] ss = < "aabb", "aa", "cc", "aac" >; Pattern p = Pattern.compile("aabb"); Matcher m = p.matcher(""); for (String s : ss) < m.reset(s); if (m.matches()) < System.out.printf("%-4s : match%n", s); >else if (m.hitEnd()) < System.out.printf("%-4s : partial match%n", s); >else < System.out.printf("%-4s : no match%n", s); >> > > 
aabb : match aa : partial match cc : no match aac : no match 

Насколько я знаю, Java является единственным языком, который предоставляет эту функциональность. Также существует метод requireEnd() , который говорит вам, что больше ввода может превратить совпадение в несоответствие, но я не думаю, что это имеет значение в вашем случае.

Оба метода были добавлены для поддержки класса Scanner, поэтому он может применять регулярные выражения к потоку, не требуя, чтобы весь поток считывался в память.

«Насколько я знаю, Java — единственный язык, который предоставляет эту функциональность». — разве это не эквивалентно частичному соответствию Буста? ( boost.org/doc/libs/1_34_1/libs/regex/doc/partial_matches.html )

@Tim, я получаю «частичное совпадение», что имеет смысл, так как вы можете добавить «BC» в конец и получить совпадение (что я и сделал, и это сделал).

@poly: Да, это похоже на hitEnd() в Java; спасибо за указатель. Я не вижу никакого эквивалента для requireEnd() хотя.

@AlanMoore, почему частичное сопоставление не работает для такого шаблона: Pattern.compile («(\\ w <3>) (\\ d ) (\\ w <3>)»)?

Pattern p = Pattern.compile(expr); Matcher m = p.matcher(string); m.find(); 

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

Итак, вы хотите знать, не соответствует ли строка s регулярному выражению, но может ли быть более длинная строка, начинающаяся с s, которая будет соответствовать? Извините, Regexes не может помочь вам там, потому что у вас нет доступа к внутреннему состоянию соединителя; вы получаете только логический результат и любые группы, которые вы определили, поэтому вы никогда не знаете, почему совпадение не получилось.

Если вы готовы взломать библиотеки JDK, вы можете расширить (или, возможно, fork) java.util.regex и предоставить дополнительную информацию о процессе сопоставления. Если совпадение не получилось, потому что вход был «использован», ответ был бы правдой; если он потерпел неудачу из-за дискриминации характера или других проверок, это было бы неверно. Это похоже на большую работу, потому что ваша проблема полностью противоположна тому, что должны делать регулярные выражения.

Другой вариант: возможно, вы можете просто переопределить задачу, чтобы вы могли рассматривать ввод как регулярное выражение и сопоставлять aabb с * aa. **? Однако вы должны быть осторожны с метасимволами регулярных выражений.

Относительно вашего второго абзаца: я бы сказал: «Если совпадение не получилось, потому что вход« использовался » в любой момент во время попытки совпадения, ответ был бы верным». В конце концов, механизм регулярных выражений мог соответствовать до конца один раз, затем возвращался назад и выходил из строя, не возвращаясь к концу строки. Как при применении ^A.*BC$ к ABCD .

Читайте также:  All modules views css views

Если вы производите каждый символ регулярного выражения и расслабляете ограничения множественности, вы можете получить то, что хотите. Например, если у вас есть соответствующий шаблон «aa (abc) + bbbb», вы можете иметь шаблон «возможного соответствия» a? A? (A? B? C?) * B? B? B? B? ‘.

Этот механический способ создания шаблона с возможными совпадениями не охватывает расширенные конструкции, такие как прямые и обратные ссылки.

В приведенном примере вы можете попытаться использовать анти-шаблон для дисквалификации недопустимых результатов. Например, «^ [^ a]» скажет вам, что вы вводите «c. «, не может соответствовать вашему примеру шаблону «aabb».

В зависимости от вашего шаблона вы можете разбить его на более мелкие шаблоны, чтобы проверять и использовать несколько матчи, а затем устанавливать их границы по мере совпадения, и вы переходите к следующему. Этот подход может работать, но если вы шаблон сложный и может иметь подпункты переменной длины, вы можете в конечном итоге переопределить часть элемента управления в своем собственном коде, чтобы настроить возможные границы матча, чтобы сделать его более или менее жадным. Общая идея этого псевдокода заключалась в следующем:

boolean match(String input, Matcher[] subpatterns, int matchStart, int matchEnd) < matcher = next matcher in list; int stop = matchend; while(true)< if matcher.matches input from matchstart ->matchend< if match(input, subpatterns, end of current match, end of string)< return true; >else < //make this match less greedy stop--; >>else < //no match return false; >> > 

Затем вы можете объединить эту идею с анти-шаблонами и иметь анти-подшаблоны, и после каждого соответствия подшаблона вы проверяете следующий анти-шаблон, если он совпадает, вы знаете, что вам не удалось, в противном случае продолжить шаблон соответствия. Вероятно, вы захотите вернуть что-то вроде перечисления вместо логического (т.е. ALL_MATCHED, PARTIAL_MATCH, ANTI_PATTERN_MATCH. )

Опять же, в зависимости от сложности вашего фактического шаблона, который вы пытаетесь совместить с написанием, соответствующие суб-шаблоны/анти-шаблон могут быть трудными, если не невозможными.

Источник

Частичное совпадение строки

если s1 завершено существует в s2, то возвращается s2. у любого есть алгоритм или другой гибкий код, заранее спасибо.

вам нужен метод indexOf в классе String? — Tiago Peczenyj

5 ответы

if (s2.contains(s1)) return s2; 

это чувствительно к регистру, как чувствительность к регистру будет удалена — ибрахимхалил

Да, это чувствительно к регистру. Вы можете просто создать копию строк и использовать toLowerCase(), чтобы избавиться от чувствительности к регистру. — Мичелл Бак

Вы можете использовать Java.String.indexOf(), как описано здесь.

Это довольно прямолинейно.

Вы можете использовать contains() метод String класс, Пожалуйста, изучите следующий пример,

public class TestClass < private String getString ( String str1, String str2 ) < if ( str2.contains (str1) ) < return str2; >else < return "-1"; >> public static void main ( String args[] ) < String s1 = "method"; String s2 = "this is wonderful method i am using"; TestClass tc = new TestClass(); System.out.println ( tc.getString(s1, s2) ); >> // Output // this is wonderful method i am using 

Проще всего было бы использовать String.contains, как в if( s2.contains(s1) ) return s2; Или вы можете использовать регулярное выражение для соответствия

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

Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками android or задайте свой вопрос.

Источник

Оцените статью