Поиск строки с подстановочными знаками - PullRequest
0 голосов
/ 07 марта 2020

Я выполняю следующее упражнение по программированию: Поиск строки с подстановочным знаком . Это утверждение:

Метод, приведенный ниже, является наиболее простым алгоритмом поиска строки. Он найдет первое вхождение слова в текстовой строке.

стог сена = весь текст

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;
    }
}

и есть код, который проходит тесты.

Ответы [ 2 ]

2 голосов
/ 07 марта 2020

В вашем «игле» есть символы, которые имеют специальное значение в регулярном выражении, а именно знак доллара $, который означает «конец строки» в регулярном выражении. Вы должны избегать таких специальных символов при создании регулярного выражения, чтобы маршировать буквальную строку. Для этого вы можете использовать метод Pattern.quote.

1 голос
/ 07 марта 2020

Почему регулярное выражение не соответствует "... 4 $ &% $ --..." inside "- ..,. 44 $ &% $ -,.,"?

Как минимум $ является регулярным выражением , совпадающим в конце строки. Это не то, что вы хотите. вам нужно заменить $ на \$ соответственно "\\$"

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...