2016-09-29 2 views
2

Как я могу собрать регулярное выражение для разделения строки fiql (пример ниже), который разделяет условия с точкой с запятой. Проблема состоит в том, что полуколоны также могут быть в строке.Регулярное выражение строк с запятой в данных

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

query.split("(;)[^;]*==) 

Но это работает только для первого ключа.

Пример строки:

Key1==value1; key2==val;ue2;key3==value3 

Target является массив или список: key1==value1, key2==val;ue2, key3==value3 Проблема здесь является точка с запятой в значении 2 вызывает раскол.

Любая идея?

ответ

2

Похоже, что вы хотите разбить на ;, только если у него есть ==, но и не имеет ; между ним и этим ==.

Вы купили почти там. Ваш код должен выглядеть

split(";(?=[^;]*==)") 

обратите внимание, что (?=...) часть positive look-ahead, который просто проверяет, если после ; существует часть, которая может соответствовать подвыражения [^;]*==, но не включает в себя эту роль в финальном матче, так что не будет исчезают после расщепления (это zero-length матч).

DEMO:

String str = "Key1==value1; key2==val;ue2;key3==value3"; 
for (String s : str.split(";(?=[^;]*==)")){ 
    System.out.println(s); 
} 

Выход:

Key1==value1 
key2==val;ue2 
key3==value3 

Если вы также хотите избавиться пространство перед key2 затем сделать его частью разделителем, на котором вы хотите разделить. Поэтому пусть регулярное выражение соответствует не только ;, но и окружающим его пробелам. Ноль или более пробельные символы могут быть представлены \s* так что ваш код может выглядеть

split("\\s*;\\s*(?=[^;]*==)") 
+0

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

+1

@bashnesnos Правда, этот подход может быть не лучшим с точки зрения производительности из-за обратного отслеживания, но я не уверен, будет ли это O (N^2) (если это то, что вы подразумеваете под * квадратичным *). Я подозреваю, что он будет ближе к O (2 * N). Это регулярное выражение будет итерировать, чтобы найти ';', тогда look-ahead попытается найти совпадение для '[^;] * ==', поэтому '[^;] *' может выполнять итерацию max до следующего ';'. Таким образом, только область символов, которые могут повторяться несколько раз, совпадают с символами '[^;] *'. Но они по-прежнему повторяются только max 2 раза: один раз, когда мы будем искать разделитель ';' и один раз в перспективе. – Pshemo

+0

Да, я должен был написать 2 * N. Я следовал той же логике, что и вы, но как она превратилась в квадратичную, в конце концов, я не знаю. Извините меня за замешательство :-) – bashnesnos

1

Используйте группу вместо этого. И поиск маркеров с помощью java.util.regex.Matcher в цикле:

Pattern patrn = Pattern.compile("(?>(\\w+==[\\w;]+)(?:;\\s*|$))"); 
Matcher mtchr = patrn.matcher("Key1==value1; key2==val;ue2;key3==value3"); 


while(mtchr.find()) { 
    System.out.println(mtchr.group(1)); 
} 

Yields: 
Key1==value1 
key2==val;ue2 
key3==value3 

Добавление;? не будет работать, к сожалению, так как ваши средние жетоны больше не будут заканчиваться.

+0

Ницца. Но несколько советов: (1) Строковые литералы помещаются внутри '' ... '', а не '' ... '',' '' зарезервированы для литералов типа 'char', (2) нет смысла в упаковке * целое regex * в группе, не захватывающей '' (?: regex) ', вы можете просто использовать' regex'. – Pshemo

+0

@Pshemo спасибо, я скопировал его с отличной консоли :-) Я использовал группу, не собирающую захват, чтобы избежать обратного отслеживания, но я согласен, что в данном случае это скорее предостережение. – bashnesnos

+0

Добро пожаловать. BTW '\ w' уже содержит диапазон« 0-9 », поэтому вы можете пропустить' \ d' в своем регулярном выражении. Также вы не обязаны добавлять в свой ответ «EDIT: change description». Если вы видите, что есть возможное улучшение или проблема, просто исправьте его в ответе :) – Pshemo

0

RegExp являются злыми.

если вы можете запросить, чтобы сделать минимальное изменение в строке, чтобы быть разобран, поэтому значение окружено двойным qoutes, то строка может быть как Key1=="value1"; key2=="val;ue2";key3=="value3" то этот пост поможет вам чека Java: splitting a comma-separated string but ignoring commas in quotes

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

Надеюсь, что это поможет.

+0

Ну, это не попытка разбора произвольного XHTML с регулярным выражением здесь :-) Почему бы и нет. Если это не так важно, чтобы критическое регулярное выражение должно было сделать трюк. – bashnesnos

+1

абсолютно, согласен. во всяком случае, фрагмент кода должен быть быстрее, тем не менее :) –

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