Я выполняю следующее упражнение по программированию: Поиск строки с подстановочным знаком . Это утверждение:
Метод, приведенный ниже, является наиболее простым алгоритмом поиска строки. Он найдет первое вхождение слова в текстовой строке.
стог сена = весь текст
needle = searchword
wildcard = _
find («ударить», «я ударю тебя»); // return 7
Метод поиска уже выполнен.
Проблема заключается в использовании подстановочных знаков в игле. Если у вас есть _ в игле, он будет соответствовать любому символу в стоге сена.
Обычный алгоритм поиска строки найдет первое вхождение слова (иглы) в тексте (стог сена), начиная с индекса 0 Вот так:
находка («ударить», «Я ударю по тебе»); return 7
Подстановочный знак в игле будет соответствовать любому символу в стоге сена. Метод должен работать на любых типах игл и сенокосов. Вы можете предположить, что игла короче (или равна) стога сена.
find ("g__d", "Это хорошо, когда ты президент"); // возвращаем 11
Если нет совпадения, метод должен возвращать -1
Мы написали следующий код:
import java.util.regex.*;
public class SearchEngine {
static int find(String needle, String haystack){
System.out.println("needle: "+needle);
System.out.println("haystack: "+haystack);
String regex = needle.replace("_",".");
if(regex.equals(needle)){
return haystack.indexOf(needle);
}
System.out.println("regex: "+regex);
Matcher m = Pattern.compile(regex).matcher(haystack);
int pos = -1;
if(m.find()){
pos = m.start();
}
System.out.println("pos: "+pos);
return pos;
}
}
Мы нашли любопытный тест где он не проходит. Будучи тестовыми примерами:
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class WildsTest {
String haystack = "Once upon a midnight dreary, while I pondered, weak and weary";
@Test
public void normalSearchTest(){
assertEquals(0,SearchEngine.find("Once", haystack));
assertEquals(12, SearchEngine.find("midnight", haystack));
assertEquals(-1, SearchEngine.find("codewars", haystack));
}
@Test
public void wildSearchTest(){
assertEquals(5, SearchEngine.find("_po_", haystack));
assertEquals(12, SearchEngine.find("___night", haystack));
assertEquals(3, SearchEngine.find("___4$&%$--___", "-..,.44$&%$--,.,"));
}
}
В последнем случае ничего не получается:
needle: ___4$&%$--___
haystack: -..,.44$&%$--,.,
regex: ...4$&%$--...
pos: -1
Почему причина в том, что регулярное выражение не соответствует "... 4 $ &% $ --... "inside" - ..,. 44 $ &% $ -,., "?
Мы также прочитали:
РЕДАКТИРОВАНИЕ:
Мы следовали предложению @Alex и пытался использовать Pattern.quote:
import java.util.regex.*;
public class SearchEngine {
static int find /*?*/ (String needle, String haystack){
System.out.println("needle: "+needle);
System.out.println("haystack: "+haystack);
String regex = needle.replace("_",".");
if(regex.equals(needle)){
return haystack.indexOf(needle);
}
System.out.println("regex: "+regex);
String quotedRegex = Pattern.quote(regex);
System.out.println("quotedRegex: "+quotedRegex);
Matcher m = Pattern.compile(quotedRegex).matcher(haystack);
int pos = -1;
if(m.find()){
pos = m.start();
}
System.out.println("pos: "+pos);
return pos;
}
}
Однако мы нашли следующую трассировку:
needle: _po_
haystack: Once upon a midnight dreary, while I pondered, weak and weary
regex: .po.
quotedRegex: \Q.po.\E
pos: -1
expected:<5> but was:<-1>
Как мы можем использовать Pattern.quote для поиска с использованием символов подстановки?
Кроме того, мы следовали предложению @ s.fuhrm и заменили символы на спецификации в данном случае это значение $, где "\\ $"
import java.util.regex.*;
public class SearchEngine {
static int find /*?*/ (String needle, String haystack){
System.out.println("needle: "+needle);
System.out.println("haystack: "+haystack);
String regex = needle.replace("_",".");
if(regex.equals(needle)){
return haystack.indexOf(needle);
}
System.out.println("regex: "+regex);
Matcher m = Pattern.compile(regex.replace("$","\\$")).matcher(haystack);
int pos = -1;
if(m.find()){
pos = m.start();
}
System.out.println("pos: "+pos);
return pos;
}
}
и есть код, который проходит тесты.