2014-12-22 4 views
2

Я делаю синтаксический анализатор ключа, где входная строка принимает форму key:"value",key2:"value". Ключи могут содержать символы , A-Z и 0-9, а значения могут содержать любой символ, но :, ,, " и \ должны иметь префикс обратной косой черты. Запятые используются для разделения пар ключ-значение, но не нужны после последней пары.Соответствие шаблону ключевого значения regex

До сих пор у меня есть ([a-zA-Z0-9]+):"(.*)", который будет соответствовать большинству ключей и значений, но, очевидно, он не сможет обрабатывать больше одной пары или если какой-либо из «контрольных» символов не отображается. (?<=\\)[:,"\\], похоже, соответствует всем экранированным символам, но не соответствует никаким «нормальным» символам.

Есть ли способ проверить разделение запятой и сопоставить все экранированные символы «управления», а также обычные? Является ли это чем-то более подходящим для реализации без регулярного выражения, или это потребует нескольких шаблонов в последовательности?

Некоторые примеры:

вход: joe:"bread",sam:"fish" выход: joe -> breadsam -> fish

вход: joe:"Look over there\, it's a shark!",sam:"I like fish." выход: joe -> Look over there, it's a shark!sam -> I like fish

+0

Можете ли вы привести пример вместе с ожидаемым выходом? –

+0

Почему вы не используете 'input_string.split (", ")' then loop results и 'result.split (": ")', тогда у вас есть пары ключей -> val в цикле, чтобы сделать, как вам заблагорассудится. – gwillie

+0

Может ли новая строка быть частью ценности? И как это указано в значении? – nhahtdh

ответ

1

Предполагая, что \, за которым следует любой символ, кроме терминатора линии, указывает символ, следующий за ним.

Вы можете использовать следующее регулярное выражение, чтобы соответствовать все экземпляры пар ключ-значение:

"([a-zA-Z0-9]+):\"((?:[^\\\\\"]|\\\\.)*+)\"" 

Добавить \\s* до и после :, если вы хотите, чтобы обеспечить свободное расстояние.

Это то, что видит механизм регулярных выражений:

([a-zA-Z0-9]+):"((?:[^\\"]|\\.)*+)" 

Квантификатор * сделан притяжательные *+, так как 2 ветви [^\\"] и \\. являются взаимоисключающими (не строка не может соответствовать как в то же время) , Он также избегает StackOverflowError в реализации Oracle Pattern.

Использование регулярных выражений выше в цикле Matcher:

Pattern keyValuePattern = Pattern.compile("([a-zA-Z0-9]+):\"((?:[^\\\\\"]|\\\\.)*+)\""); 
Matcher matcher = keyValuePattern.matcher(inputString); 

while (matcher.find()) { 
    String key = matcher.group(1); 

    // Process the escape sequences in the value string 
    String value = matcher.group(2).replaceAll("\\\\(.)", "$1"); 

    // ... 
} 

В общем случае, в зависимости от сложности управляющих последовательностей (например, \n, \uhhhh, \xhh, \0), вы можете написать отдельную функцию для их анализа. Однако с предположением выше достаточно однострочного.

Обратите внимание, что это решение не заботится о разделителях. И он пропустит недопустимый ввод в ближайшее совпадение. В примере неправильного ввода ниже, раствор выше будет пропускать abc:" в начале и благополучно соответствовать xyz:"text text" драм more:"pair" в виде пар ключ-значение:

abc:"xyz:"text text", more:"pair" 

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

"(?:^|(?!^)\\G,)([a-zA-Z0-9]+):\"((?:[^\\\\\"]|\\\\.)*+)\"" 

версия Free-разнос:

"(?:^\s*|(?!^)\\G\s*,\s*)([a-zA-Z0-9]+)\s*:\s*\"((?:[^\\\\\"]|\\\\.)*+)\"" 
+0

Я закончил разбиение строки на пары с ключом, затем используя '^ ([a-zA-Z0-9] +):" ((?: \ \ [: "\\,] | [^:" \\,]) *) "$' благодаря вашему ответу. Сначала это разделение позволяет мне дать более описательную ошибку, если что-то пойдет не так. Я не уверен, что это самый эффективный способ сделать это, но, похоже, он работает для всех тестовых случаев, которые у меня были, и отклонил все искаженные. – user2248702

2

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

([a-zA-Z0-9]+):"(.*?)(?<!\\)" 

ИЛИ

([a-zA-Z0-9]+):"(.*?)"(?=,[a-zA-Z0-9]+:"|$) 

DEMO

Java регулярное выражение будет,

"([a-zA-Z0-9]+):\"(.*?)(?<!\\\\)\"" 

(?<!\\)" отрицательна утверждает, что с просмотром назад двойные кавычки не будут предваряться символом обратной косой. В Java, чтобы соответствовать символ обратной косой черты, что вам нужно, чтобы избежать обратной косой черты в вашем шаблоне ровно три раза, то есть, \\\\

DEMO

String s = "joe:\"Look over there\\, it's a shark!\",sam:\"I like fish.\""; 

Matcher m = Pattern.compile("([a-zA-Z0-9]+):\"(.*?)(?<!\\\\)\"").matcher(s); 
    while(m.find()) 
    { 
     System.out.println(m.group(1) + " --> " + m.group(2)); 
    } 
} 

Выход:

joe --> Look over there\, it's a shark! 
sam --> I like fish. 

ИЛИ

String s = "joe:\"Look over there\\, i\\\"t's a shark!\",sam:\"I like fish.\""; 

Matcher m = Pattern.compile("([a-zA-Z0-9]+):\"((?:\\\\\"|[^\"])*)\"").matcher(s); 
    while(m.find()) 
    { 
     System.out.println(m.group(1) + " --> " + m.group(2)); 
    } 
} 

Выход:

joe --> Look over there\, i\"t's a shark! 
sam --> I like fish. 
+0

. Есть еще проблемы, но я понимаю, что нет смысла в том, чтобы ответить на этот вопрос, поскольку вопрос не указан. – nhahtdh

+0

Кстати, ваше регулярное выражение не будет выполнено для значения 'abc:" \\ "' – nhahtdh

+0

см. Мое обновление ... –

Смежные вопросы