Подтвердить что ты не робот

Как можно улучшить этот код Java, чтобы найти подстроку в строке?

Недавно меня попросили отправить решение проблемы на работу.

Проблема. Найдите подстроку в строке.

Input: "Little star deep dish pizza sure is fantastic."  
Search: "deep dish pizza"  
Output: "Little star [[HIGHLIGHT]]deep dish pizza[[ENDHIGHLIGHT]] sure is fantastic."

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

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

Мое решение не было принято. Как я мог улучшить его? Я знаю, я мог бы использовать:

Мой вопрос:

  • Что думают технологические компании, когда они просматривают код для работы. Я отправил код в тот же день, это поможет?

  • В одном из комментариев он отметил, что он выглядит как школьный код, а не код производства. Как? Любые предложения?

Мое решение:
FindSubString.java

/**
 * FindSubString.java: Find sub-string in a given query
 * 
 * @author zengr
 * @version 1.0
 */

public class FindSubstring {
    private static final String startHighlight = "[[HIGHLIGHT]]";
    private static final String endHighlight = "[[ENDHIGHLIGHT]]";

    /**
     * Find sub-string in a given query
     * 
     * @param inputQuery: A string data type (input Query)
     * @param highlightDoc: A string data type (pattern to match)
     * @return inputQuery: A String data type.
     */
    public String findSubstringInQuery(String inputQuery, String highlightDoc) {
        try {

            highlightDoc = highlightDoc.trim();

            if (inputQuery.toLowerCase().indexOf(highlightDoc.toLowerCase()) >= 0) {
                // update query if exact doc exists
                inputQuery = updateString(inputQuery, highlightDoc);
            }

            else {
                // If exact doc is not in the query then break it up
                String[] docArray = highlightDoc.split(" ");

                for (int i = 0; i < docArray.length; i++) {
                    if (inputQuery.toLowerCase().indexOf(docArray[i].toLowerCase()) > 0) {
                        inputQuery = updateString(inputQuery, docArray[i]);
                    }
                }
            }
        } catch (NullPointerException ex) {
            // Ideally log this exception
            System.out.println("Null pointer exception caught: " + ex.toString());
        }

        return inputQuery;
    }

    /**
     * Update the query with the highlighted doc
     * 
     * @param inputQuery: A String data type (Query to update)
     * @param highlightDoc: A String data type (pattern around which to update)
     * @return inputQuery: A String data type.
     */
    private String updateString(String inputQuery, String highlightDoc) {
        int startIndex = 0;
        int endIndex = 0;

        String lowerCaseDoc = highlightDoc.toLowerCase();
        String lowerCaseQuery = inputQuery.toLowerCase();

        // get index of the words to highlight
        startIndex = lowerCaseQuery.indexOf(lowerCaseDoc);
        endIndex = lowerCaseDoc.length() + startIndex;

        // Get the highlighted doc
        String resultHighlightDoc = highlightString(highlightDoc);

        // Update the original query
        return inputQuery = inputQuery.substring(0, startIndex - 1) + resultHighlightDoc + inputQuery.substring(endIndex, inputQuery.length());
    }

    /**
     * Highlight the doc
     * 
     * @param inputString: A string data type (value to be highlighted)
     * @return highlightedString: A String data type.
     */
    private String highlightString(String inputString) {
        String highlightedString = null;

        highlightedString = " " + startHighlight + inputString + endHighlight;

        return highlightedString;
    }
}

TestClass.java

/**
 * TestClass.java: jUnit test class to test FindSubString.java
 * 
 * @author zengr
 * @version 1.0
 */

import junit.framework.Test;
import junit.framework.TestCase;
import junit.framework.TestSuite;

public class TestClass extends TestCase
{
    private FindSubstring simpleObj = null;
    private String originalQuery = "I like fish. Little star deep dish pizza sure is fantastic. Dogs are funny.";

    public TestClass(String name) {
        super(name);
    }

    public void setUp() { 
        simpleObj = new FindSubstring();
    }

    public static Test suite(){

        TestSuite suite = new TestSuite();
        suite.addTest(new TestClass("findSubstringtNameCorrect1Test"));
        suite.addTest(new TestClass("findSubstringtNameCorrect2Test"));
        suite.addTest(new TestClass("findSubstringtNameCorrect3Test"));
        suite.addTest(new TestClass("findSubstringtNameIncorrect1Test"));
        suite.addTest(new TestClass("findSubstringtNameNullTest"));

        return suite;
    }

    public void findSubstringtNameCorrect1Test() throws Exception
    {
        String expectedOutput = "I like fish. Little star deep [[HIGHLIGHT]]dish pizza[[ENDHIGHLIGHT]] sure is fantastic. Dogs are funny.";
        assertEquals(expectedOutput, simpleObj.findSubstringInQuery(originalQuery, "dish pizza"));
    }

    public void findSubstringtNameCorrect2Test() throws Exception 
    {
        String expectedOutput = "I like fish. Little star [[HIGHLIGHT]]deep dish pizza[[ENDHIGHLIGHT]] sure is fantastic. Dogs are funny.";
        assertEquals(expectedOutput, simpleObj.findSubstringInQuery(originalQuery, "deep dish pizza"));
    }

    public void findSubstringtNameCorrect3Test() throws Exception 
    {
        String expectedOutput = "Hello [[HIGHLIGHT]]how[[ENDHIGHLIGHT]] are [[HIGHLIGHT]]you[[ENDHIGHLIGHT]]r?";
        assertEquals(expectedOutput, simpleObj.findSubstringInQuery("Hello how are your?", "how you"));
    }

    public void findSubstringtNameIncorrect1Test() throws Exception 
    {
        String expectedOutput = "I like fish. Little star deep dish pizza sure is fantastic. Dogs are funny.";
        assertEquals(expectedOutput, simpleObj.findSubstringInQuery(originalQuery, "I love Ruby too"));
    }

    public void findSubstringtNameNullTest() throws Exception
    {
        String expectedOutput = "I like fish. Little star deep dish pizza sure is fantastic. Dogs are funny.";
        assertEquals(expectedOutput, simpleObj.findSubstringInQuery(originalQuery, null));

    }
}
4b9b3361

Ответ 1

Несколько комментариев;

  • Вы выделяете только первое обнаружение строки поиска.
  • Вы предполагаете, что соответствие в нижнем регистре прекрасное. Если это не было указано как требование, было бы лучше предоставить два метода: один, который относится к делу, и тот, который игнорирует случай.
  • Я бы, вероятно, проверил данные параметры и выбросил NPE, если любой из них был нулевым. Это было бы первым, что сделал мой метод. Я бы четко документировал это поведение в javadoc.
  • Твой метод плохой; findSubstringInQuery Основная задача - не находить, она должна выделяться, а часть inQuery является сверхплотной. Просто вызовите метод highlight или, может быть, highlightIgnoreCase, если у вас будет highlight, который относится к делу.
  • Имена параметров вашего метода плохие. Я просмотрел вашу сигнатуру метода 10 раз и все еще должен смотреть на тело метода, чтобы напомнить себе, какой аргумент является поисковым термином и который является поисковым текстом. Вызовите их searchTerm и text.
  • Производственный код не использует пакет по умолчанию.
  • Производственный код не использует System.out.println().
  • Ваш javadoc нуждается в улучшении, он должен сообщить пользователю все, что им нужно знать о коде.
  • Я бы рассмотрел использование статических методов для класса без переменных класса.
  • Я также хотел бы позволить пользователю указать свои собственные маркеры выделения начала и конца (я бы не использовал статические методы, если бы сделал это).
  • Я бы не trim(), если это не было указано как требование. Если бы я это сделал, то, очевидно, это поведение будет задокументировано в javadoc.

Я бы не стал беспокоиться об алгоритме, используемом для поиска, Кнут-Моррис-Пратт выглядит неплохо, но они не должны ожидать, что вы узнаете об этом и реализуете его, если спецификация задания специально не задала опыт/опыт в поиске строк.

Ответ 2

Если бы этот код был представлен мне для просмотра, я бы подумал:

  • Код слишком многословный и сложный, где это не обязательно. Все это можно сделать небольшим методом в десяти строках кода, включая все проверки работоспособности. Вероятно, этот метод должен быть статическим.
  • Ваш код делает то, что (я полагаю) не просил. Вас попросили найти подстроку в строке. Если он не найден, то это прекрасно - не нужно разделять подстроку на слова и искать каждое отдельное слово.
  • Если они не попросили вас удалить ведущие и конечные пробелы, я бы не позвонил trim()
  • Я бы не включил вызовы в toLowerCase(), если явно не задал вопрос, хотя я бы добавил комментарий, в котором они могли бы быть добавлены, если это необходимо. В любом случае, даже если поиск предназначен для нечувствительности к регистру, в вашем коде слишком много избыточных вызовов toLowerCase().
  • Вам не нужно ловить NullPointerException - вместо этого вы должны убедиться, что это исключение никогда не выбрасывается.

Ответ 3

Похоже, вы пропустили суть проблемы. В оригинальной постановке проблемы говорится:

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

Похоже, они хотели, чтобы вы вернули хороший фрагмент, а не просто выделили слова на исходном входе. Если вход был длинным, вы хотели бы вернуть меньший фрагмент текста с выделенными словами.

Одним из возможных подходов может быть:

  • Найдите самый маленький фрагмент текста, содержащий все входы (или наиболее возможные входы).
  • Разверните фрагмент, чтобы включить прилагаемые предложения, если это возможно.
  • Если результат больше максимальной длины, скажем 100, обрезайте фрагмент, возможно, вставляя эллипсис где-то внутри.

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

Ответ 4

Я не знаю, что я чего-то не хватает, но я бы написал простой блок кода, используя indexOf() и другие строковые методы. В зависимости от проблемы проблемы, я бы, вероятно, использовал метод StringBuilder.insert() для ввода выделения. Я бы не стал делать токенизацию и цикл, как вы это делали. Я бы оправдал это, сказав, что это самое простое решение проблемы, как указано. KISS - лучший подход для открытия таких вопросов.

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

Я также заметил уловку нулевого указателя. Хорошая идея, если вы знаете, где это может произойти и собираетесь что-то сделать. Но поскольку вы просто регистрируетесь, возможно, вам следовало бы сделать более общий улов. Например, может ли ваш код вызвать исключение IndexOutOfBoundsException. Поэтому я бы хотел поймать Exception или Throwable.

Другая вещь, которую я прошу, - это определение того, что они считают "производственным кодом". На первый взгляд это звучит достаточно просто, но мой опыт в том, что его можно интерпретировать по-разному.

Реальная проблема в том, что они будут ожидать определенные вещи, и вы их не знаете. Таким образом, вы кодируете то, что работает для вас, и надеемся, что оно соответствует ожидаемому.

Ответ 5

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

class MarkedText {
    String highlightDoc;
    String inputQuery;
    List<Range> ranges;
}

class Range {
    int offset;
    int length;
}

public MarkedText findSubstringInQuery(String inputQuery, String highlightDoc) {
    [...]
}

Ответ 6

Вы хотите подбирать частичные слова в случае разрыва запроса? Вы также не учитываете, что строка поиска содержит слово "HIGHLIGHT".

Например, попробуйте следующее:

Ввод: "Маленькая пицца для блюд с маленькой звездой - это фантастика".
Поиск: "ВЫСОТА"
Выход: (возможно, не то, что вы хотите)