Я пытаюсь написать регулярное выражение на F #, которое будет соответствовать таким вещам
.float -.05, 2.4
.float 31.1234
.float -0.5, 1.0, 1.1
Я пробую что-то вроде этого
let matchFloat input =
let matches = Regex(@"(\.float )?(?<float>[+-]?\d*\.\d+)").Matches(input)
([for m in matches -> m.Groups.["float"].Value, matches.Count > 0)
Какой вид работает, но у меня то же самое для .double, и независимо от того, какое первое в моем выражении соответствия будет совпадать, так как я делаю «встречается 0 или 1 раз», это означает, что строки с плавающей точкой номера точек, следующие за любой директивой, будут обрабатываться одинаково.
Итак, как мне убедиться, что .float существует, не выполняя input.StartsWith (...)? Я знаю, что есть способ написать это регулярное выражение, чтобы оно соответствовало надлежащим образом, и m.Groups. ["Float"]. Value вернет только то, что мне нужно, без удаления пробелов или запятых после факта.
Я возился с этой штукой часами и просто не могу заставить ее делать то, что я хочу. Я пробовал использовать функции lookbehind / lookahead и несколько других вещей, но не повезло.
3 ответа
Что ж, это поможет вам перейти к шагу 1 по ремонту Linux-машины
Вы можете использовать положительный просмотр назад в сочетании с чередованием, чтобы захватить либо .float
, либо .decimal
в начале строки в группу, а затем проверить, какая из них была захвачена. Сама ретроспектива не способствует первичному захвату, поэтому числовые цифры по-прежнему являются единственной вещью в «группе 0».
Тогда мой любимый трюк - добавив .*
в ретроспективу (после float
или decimal
), вы можете успешно вернуть несколько совпадений из входной строки, каждое из которых имеет начальное .float
или .decimal
, но затем при каждом увеличении масштаба вперед захватывается другой набор цифр.
Надеваем на него лук с небольшим шрифтом DU, чтобы представить два случая:
type DataPoint =
| Float of string
| Decimal of string
let parse input =
let patt = "(?<=^\.((float)|(decimal)).*(,?\s+))[+-]?\d*\.\d+(?=\s*(,|$))"
Regex.Matches(input, patt)
|> Seq.cast<Match>
|> Seq.map (fun m ->
match (m.Groups.[2].Success, m.Groups.[3].Success) with
| (true, false) -> Float(m.Value)
| (false, true) -> Decimal(m.Value)
| _ -> failwith "??")
|> List.ofSeq
// positive cases
parse ".float -.05, 2.4" // [Float "-.05"; Float "2.4"]
parse ".float 31.1234" // [Float "31.1234"]
parse ".float -0.5, 1.0, 1.1" // [Float "-0.5"; Float "1.0"; Float "1.1"]
parse ".decimal 123.456, -22.0" // [Decimal "123.456"; Decimal "-22.0"]
// negative cases, plucks out valid bits
parse ".decimal xyz,,.., +1.0, .2.3.4, -.2 " // [Decimal "+1.0"; Decimal "-.2"]
parse ".float 1.0, 2.0-, 3." // [Float "1.0"]
Обратите внимание, что я просто полагался на номера групп, вы можете быть более осторожными и использовать именованные группы.
Также стоит отметить, что .NET - это одна из немногих сред регулярных выражений, которая поддерживает полное чередование и .*
соответствует в ретроспективе, поэтому это может быть непереносимым.
Изменить: я несколько укрепил шаблон против негативных отзывов на основе отзывов. Все еще не пуленепробиваемый.
На самом деле я не вижу причин, по которым в этом случае Regex вообще может быть полезен. Использование строковых функций и функций синтаксического анализа системы является более читаемым и безопасным способом анализа ввода. Заимствование DataPoint из ответа @ latkin:
open System
type DataPoint =
| Float of float
| Decimal of decimal
let listparse parser mapper =
List.choose (fun f -> match parser f with true, v -> Some (mapper v) | _ -> None)
let parse (input: string) =
match Array.toList (input.Split([|',';' '|])) with
| ".float"::rest -> rest |> listparse Double.TryParse Float
| ".decimal"::rest -> rest |> listparse Decimal.TryParse Decimal
| _ -> []
А используя дополнительные параметры в методах .TryParse (), вы можете легко обрабатывать более сложные входные форматы с плавающей запятой, такие как представление экспоненты (например, 1.3E5)
Попробуйте это \.float [+-]?[0-9\., ]+
, а также обратитесь к этому (http://regex101.com/r/kW6zZ1/1)
.float ,,,,,
, .float 5.4.3.,.0
и т. д. 2. Он не захватывает все допустимые строки, такие как .float 1.5, -2.5
3. Он не дает возможности извлеките отдельные группы цифр, поскольку OP ясно дал понять, что это цель.
Похожие вопросы
Новые вопросы
regex
Регулярные выражения предоставляют декларативный язык для сопоставления шаблонов в строках. Они обычно используются для проверки строк, разбора и преобразования. Укажите язык (PHP, Python и т. д.) или инструмент (grep, VS Code, Google Analytics и т. д.), который вы используете. Не размещайте вопросы, требующие объяснения того, что означает символ или чему будет соответствовать конкретное регулярное выражение.