Разбор списка отдельных значений ключа с подчеркиванием

#java #regex

#java #регулярное выражение

Вопрос:

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

Идентификаторы:

 {PG, PGN, T, TN, Axis}
  

Имена файлов:

 Measurement_2020-08-10 13.08.04.578_Batch counter_41.0_PGN_1338_TN_1337
Measurement_2020-08-10 13.05.15.065_Batch counter_39.0_PG_under_score_program_name_T_1337
Measurement_2020-08-10 13.05.15.065_Batch counter_39.0_Axis_unsolvable_PG_T_bla
  

Ожидаемые результаты:

 {[PGN,1338],[T,1337]}
{[PG,under_score_program_name],[T,1337]}
ambiguous. two possible solutions {[Axis,unsolvable_PG],[T,bla]} OR {[Axis,unsolvable],[PG,T_bla]}
  

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

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

Добавлен тег regex, потому что это можно было бы решить с помощью одного.

Заранее благодарю вас за предложения 🙂

Комментарии:

1. Если вы можете определить это довольно быстро, вам нужно объяснить (пожалуйста, в вопросе, а не в комментариях), каковы именно правила. Почему «Ось, неразрешимая_pg», а не «Axis_unsolvable, PG»? У вас есть список идентификаторов заранее?

2. Да, я сказал об этом в своем посте. И я могу определить это довольно быстро, потому что я знаю, что это всегда должно быть KEY_VALUE_KEY2_VALUE2 и так далее.

3. Тем не менее, я не понимаю, откуда вы знаете, что это «[Axis, unsolvable_PG], [T, bla]», а не «[Axis, unsolvable], [PG, T_bla]».

4. Хороший довод. На самом деле я этого не делаю. Я предполагаю, что некоторые случаи будут неразрешимыми. Я предполагаю, что в этом случае оба решения приемлемы.

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

Ответ №1:

обычный старый StringTokenizer…

 public class FilenameParser {

    private Set<String> keywords;

    public FilenameParser(Set<String> keywords) {
        this.keywords = keywords;
    }

    public Map<String,String> parse(String filename) {
        Map<String, String> results = new HashMap<String, String>();

        StringTokenizer tokenizer = new StringTokenizer(filename, "_");
        while(tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();
            nextToken(token, tokenizer, results);
        }

        return results;
    }

    private void nextToken(String token, StringTokenizer tokenizer, Map<String, String> results) {
        if(keywords.contains(token)) {
            boolean keywordFound = false;
            String key = token;
            List<String> value = new ArrayList<>();
            while(tokenizer.hasMoreTokens() amp;amp; ! keywordFound ) {
                token = tokenizer.nextToken();
                if(keywords.contains(token)) {
                    keywordFound = true;

                    nextToken(token, tokenizer, results);

                } else {
                    value.add(token);
                }
            }

            results.put(key, value.stream().reduce((left, right) -> {
                return left   "_"   right;
            }).orElse(""));
        }
        return;
    }
}
  

Использование:

 public class Starter {

    public static void main(String[] args) {

        Set<String> keywords = new HashSet<String>();
        keywords.addAll(Arrays.asList("PG", "PGN", "T", "TN", "Axis"));

        FilenameParser parser = new FilenameParser(keywords);

        Map<String,String> result = parser.parse("Measurement_2020-08-10 13.05.15.065_Batch counter_39.0_Axis_unsolvable_PG_T_bla");
        System.out.println(result);
    }
}
  

Результат: {T = bla, PG=, Axis = неразрешимо}

Комментарии:

1. В OP сказано, что результат должен быть {T=bla,Axis=unsolvable_PG} для этого файла.

2. код можно отредактировать, чтобы соответствовать этому результату, просто верните пустой ключ из nextToken и добавьте его к предыдущим значениям… но это выглядит двусмысленно. Использование шаблона key_value_key2_value2, как указано в комментариях, PG является ключом, для которого нет значения

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