Как сделать регулярное выражение «не содержит»

У меня небольшая проблема с созданием регулярных выражений. Ожидаемый ввод:

blahblahblah, blahblahblah, 'blahblahblah', "blahblahblah, asdfd"

Мне нужно получить слова, разделенные запятой, в массив. Но я не могу использовать функцию разделения, потому что запятая может встречаться и в строках. Итак, ожидаемый результат:

arr[0] = blahblahblah
arr[1] = blahblahblah
arr[2] = 'blahblahblah'
arr[3] = "blahblahblah, asdfd"

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


person user35443    schedule 04.04.2012    source источник
comment
Мне просто нужно получить слова из ввода, разделенные запятой.   -  person user35443    schedule 04.04.2012
comment
подозрительно похоже на формат CSV.   -  person Jodrell    schedule 04.04.2012
comment
Да, мне нужны значения, разделенные запятой.   -  person user35443    schedule 04.04.2012
comment
за исключением случаев, когда запятая содержится в двойных кавычках, но как насчет двойных кавычек внутри двойных кавычек, это разрешено?   -  person Jodrell    schedule 04.04.2012
comment
Итак, это на самом деле какая-то строка CSV или эта проблема ограничена именно вашим примером и просто псевдо CSV?   -  person Jodrell    schedule 04.04.2012
comment
CSV не поддерживает 'blahblah', только blahblah или "blahblah"   -  person Ωmega    schedule 04.04.2012
comment
Как вы хотите обрабатывать такие строки, как "First "" item", поскольку в CSV это одна строка, потому что "" преобразуется в " внутри строкового элемента...   -  person Ωmega    schedule 04.04.2012
comment
Это вариант классической задачи XY. Ваша реальная проблема заключается в том, как разделить ввод запятыми, кроме тех, что в кавычках. Название вашего вопроса не упоминает о вашей реальной проблеме! Это снижает вероятность того, что вы получите необходимую помощь. Вы ограничиваете пул отвечающих людьми, которые достаточно заинтересованы в проблеме Y, чтобы читать дальше, и достаточно знают о проблеме X, чтобы дать хорошее решение.   -  person Kevin    schedule 04.04.2012
comment
Не уверен, как вы хотите обрабатывать пробелы между элементами и новыми строками...   -  person Ωmega    schedule 04.04.2012
comment
Я предлагаю вам преобразовать ввод в стандарт CSV, а затем использовать некоторые методы для такого стандарта...   -  person Ωmega    schedule 04.04.2012


Ответы (4)


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

string line = <YourLine>
var result = new StringBuilder();
var inQuotes = false;

foreach(char c in line)
{
    switch (c)
    {
        case '"':
            result.Append()
            inQuotes = !inQuotes;
            break;

        case ',':
            if (!inQuotes)
            {
                yield return result.ToString();
                result.Clear();
            }

        default:
            result.Append()
            break;                
    }
}
person Jodrell    schedule 04.04.2012
comment
user35443 также хочет поддерживать ', а не только ", даже если это не стандартное поведение... - person Ωmega; 04.04.2012
comment
@user35443 user35443 - Тогда вам следует отредактировать свой вопрос, потому что вы приняли ответ, который не соответствует тому, о чем задается вопрос ... И ТАКОЕ здесь и для других читателей, так что не путайте их. - person Ωmega; 04.04.2012
comment
Не рекомендуется использовать блоки yield return и fallthrough case. Тем не менее, мне нравится концепция. Быстро и легко понять. Также: @stackoverflow: простое исправление. - person Mooing Duck; 04.04.2012
comment
@MooingDuck - я хотел отредактировать вопрос, а не ответ. Ваше редактирование делает код бесполезным, так как теперь он будет соответствовать "one', 'two" как два элемента! - person Ωmega; 04.04.2012
comment
@stackoverflow: Ах, не думал о вложенности. Я откатил редактирование, это гораздо более существенное редактирование, чем я думал. - person Mooing Duck; 04.04.2012

Я не уверен, что это самый оптимальный вариант, но он дал правильный результат из вашего тестового примера на http://derekslager.com/blog/posts/2007/09/a-better-dotnet-regular.-expression-tester.ashx:

(?>"[^"]*")|(?>'[^']*')|(?>[^,\s]+)

Версия строки C#:

@"(?>""[^""]*"")|(?>'[^']*')|(?>[^,\s]+)"
person FishBasketGordo    schedule 04.04.2012
comment
не будет работать для "first "" item", "Second Item", Third - person Ωmega; 04.04.2012
comment
@stackoverflow - Да, и я этого не ожидал. Это требует, чтобы строки в кавычках не содержали похожих кавычек. Как я уже сказал, он выдает правильный результат для заданного (ограниченного) тестового примера. - person FishBasketGordo; 04.04.2012
comment
@FishBasketGordo - ваш код работает с ограниченной спецификацией, о чем просил пользователь 35443 ... - person Ωmega; 04.04.2012

Один из возможных подходов — разделить запятыми (используя string.Split, а не регулярное выражение), а затем перебрать результаты. Каждый результат, содержащий 0 или 2 символа ' или ", добавляется в новый список. Когда результат содержит 1 ' или ", повторно соединяйте последующие элементы (добавляя запятую), пока в результате не будет 2 ' или ", а затем добавьте их в новый список.

person Jay    schedule 04.04.2012
comment
О, это простое решение. - person Mooing Duck; 04.04.2012
comment
@MooingDuck, ты серьезно? - person Ωmega; 04.04.2012
comment
@stackoverflow: это не самый быстрый или самый элегантный ответ, но его очень просто понять, и он дает правильные результаты. Я не могу подтвердить остальные ответы, потому что эти регулярные выражения выше меня. Это и Джодрелл - единственные предложения, которые я мог сделать. - person Mooing Duck; 04.04.2012

Вместо создания собственного анализатора CSV рассмотрите возможность использования стандартного готового класс TextFieldParser, поставляемый с .NET Framework.

Либо используйте Microsoft Ace и OleDbDataReader для непосредственного чтения файлы через ADO.NET. Образец можно найти в ряде других сообщений, подобных этому. И вот этот старый пост на CodeProject, который вы можете использовать в качестве примера. Просто убедитесь, что вы ссылаетесь на последнюю версию драйвера Ace, а не на старый драйвер Jet.OLEDB.4.0.

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

person jessehouwing    schedule 04.04.2012