Мне нужно регулярное выражение PATTERN
(для использования в С#), которое будет соответствовать целочисленным значениям с 3-значными разделителями запятой, но НЕ будет возвращать запятые в полученное значение соответствия. Например, мне нужен следующий код для записи 1
, 1234
и 1234567
на консоль:
string text = "This 1 is 1,234 a 1,234,567 sentence 7,654.321.";
// NOTE: value "7,654.321" would preferably NOT match,
// but it is acceptable for now if it does
MatchCollection matches = Regex.Matches(text, PATTERN);
foreach (Match match in matches)
Console.Write(match.Value + " ");
Я НЕ МОЖЕТ вызвать Regex.Matches
а затем сделать String.Replace
чтобы удалить запятые; все это должно произойти в регулярном выражении PATTERN
(потому что все мои выражения регулярных выражений извлекаются из базы данных и не могут включать логику вне самого шаблона без большого количества кода спагетти). Как уже отмечалось, я бы предпочел не сопоставлять рациональные ценности, но это должно быть легко исправить, если я получу отключение запятой.
Следующий шаблон НЕ РАБОТАЕТ, но он, вероятно, очень близок к тому, что мне нужно:
// THIS PATTEN DOES NOT WORK!!!
// but is probably close to what I need
string PATTERN = @"([\+-]?[0-9]+[(?<=,)[0,9]{3}]*)([eE][\+]?[0-9]+)?"
Если вы удалите [(?<=,)[0,9]{3}]*
сверху, у вас есть стандартный целочисленный шаблон. Еще раз, мне нужно принять запятые в целое число, но не возвращать их как часть совпадения. Как мне изменить этот шаблон?
Соответствие регулярных выражений представляет собой целую подстроку входной строки. Это не может быть набор подстрок - это должна быть одна подстрока.
Точно так же группы захвата могут захватывать только подстроки, поэтому вы тоже не можете этого сделать.
Но поскольку вы используете.NET, вы можете попробовать действительно уродливый взломать, используя стек захвата, если вы можете позволить себе добавить код общего назначения.
Во-первых, регулярное выражение. Он упрощен до минимума, так что его легче понять:
(?:(?<concat>\d+),?)+
Ниже приведена полная версия регулярного выражения, но пока мы будем придерживаться этого.
Затем в вашем коде вы можете реализовать следующую логику:
concat
, тогда процесс как обычноmatch.Groups["concat"].Captures
Это было бы похоже на это:
public static IEnumerable<string> GetValues(string input)
{
// Suppose regex could be any regex
var regex = new Regex(@"(?:(?<concat>\d+),?)+");
foreach (Match match in regex.Matches(input))
{
// Does this regex have our special feature?
if (regex.GroupNumberFromName("concat") >= 0)
{
// Concat the captured values
var captures = match.Groups["concat"].Captures.Cast<Capture>().Select(c => c.Value).ToArray();
yield return String.Concat(captures);
}
else
{
// This is a normal regex
yield return match.Value;
}
}
}
Хорошо, это взломать, но это позволит вам сохранить логику декларативным и многоразовым способом в регулярном выражении.
Теперь полное regex, которое вы разместили, будет выглядеть примерно так в своей взломанной версии:
(?<concat>[-+])?(?<concat>[0-9]+)(?:,(?<concat>[0-9]{3}))*(?<concat>[eE][-+]?[0-9]+)?
Regex.Replace(String, MatchEvaluator)
. Просто сопоставьте что-то вроде(?:^|(?<=\s))\d{1,3}(?:,\d{3})*(?!\.\d)
и удалите запятые в функции ,