WedX - журнал о программировании и компьютерных науках

Регулярные выражения — C# ведет себя иначе, чем Perl/Python

Под Питоном:

ttsiod@elrond:~$ python
>>> import re
>>> a='This is a test'
>>> re.sub(r'(.*)', 'George', a)
'George'

Под Перлом:

ttsiod@elrond:~$ perl
$a="This is a test";
$a=~s/(.*)/George/;
print $a;
(Ctrl-D)

George

Под С#:

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Text.RegularExpressions;

namespace IsThisACsharpBug
{
  class Program
  {
    static void Main(string[] args)
    {
        var matchPattern = "(.*)";
        var replacePattern = "George";
        var newValue = Regex.Replace("This is nice", matchPattern, replacePattern);
        Console.WriteLine(newValue);
    }
  }
}

К сожалению, С# печатает:

$ csc regexp.cs
Microsoft (R) Visual C# 2008 Compiler version 3.5.30729.5420
for Microsoft (R) .NET Framework version 3.5
Copyright (C) Microsoft Corporation. All rights reserved.

$ ./regexp.exe 
GeorgeGeorge

Это ошибка в библиотеке регулярных выражений C#? Почему он печатает «Джордж» два раза, тогда как Perl и Python печатают его только один раз?

31.08.2011

  • Я думаю, что ответ в том, что каждый язык имеет свою собственную реализацию регулярных выражений. Следовательно, регулярное выражение будет вести себя по-разному в зависимости от того, с каким движком работает. 31.08.2011
  • +1 за компиляцию из командной строки. 31.08.2011

Ответы:


1

В вашем примере разница, по-видимому, заключается в семантике функции «заменить», а не в самой обработке регулярных выражений.

.net выполняет «глобальную» замену, то есть заменяет все совпадения, а не только первое совпадение.

Глобальная замена в Perl

(обратите внимание на маленькую букву "g" в конце строки =~s)

$a="This is a test";
$a=~s/(.*)/George/g;
print $a;

который производит

GeorgeGeorge

Одиночная замена в .NET

var re = new Regex("(.*)");
var replacePattern = "George";
var newValue = re.Replace("This is nice", replacePattern, 1) ;
Console.WriteLine(newValue);

который производит

George

так как он останавливается после первой замены.

31.08.2011
  • +1 Верно! Он очень легко это видит: $a=~s/(.)/X/; дает Xhis is a test под Perl. 31.08.2011

  • 2

    Мне не ясно, ошибка это или нет, но если вы измените .* на .+, он сделает то, что вы хотите. Я подозреваю, что тот факт, что (.*) соответствует пустой строке, сбивает с толку.

    Это подтверждается следующим кодом:

    using System;
    using System.Text.RegularExpressions;
    
    class Test
    {
        static void Main()
        {
            var match = Regex.Match("abc", "(.*)");
            while (match.Success)
            {
                Console.WriteLine(match.Length);
                match = match.NextMatch();
            }
        }
    }
    

    Это выводит 3, а затем 0. Изменение шаблона на "(.+)" заставляет его просто печатать 3.

    Следует отметить, что это не имеет ничего общего с C# как с языком — только со стандартными библиотеками .NET. Стоит различать язык и библиотеки — например, вы получите точно такое же поведение, если будете использовать стандартную библиотеку .NET из F#, VB, C++/CLI и т. д.

    31.08.2011

    3

    Это ошибка в библиотеке регулярных выражений С#?

    Возможно, но это на самом деле не отвечает на ваш вопрос:

    Регулярные выражения — C# ведет себя иначе, чем Perl/Python

    Различные механизмы и реализации регулярных выражений ведут себя по-разному. Иногда это явно (и включает поддержку различных элементов и синтаксиса регулярных выражений: например, использование \( и \) для группировки, а не простые круглые скобки с обратной косой чертой для группировки).

    Книга Mastering Regular Expressions (Джеффри Э.Ф. Фридл, O'Reilly) посвящена много времени, объясняя эти различия (помимо более фундаментальных различий между подходами недетерминированных конечных автоматов (NFA) и детерминированных конечных автоматов (DFA)).

    PS. Как отмечают другие, .* соответствует пустой строке, поэтому сначала "вся" ваша входная строка сопоставляется и заменяется, затем сопоставляется и заменяется пустая строка в конце ввода. Если вы хотите сопоставить все, но, возможно, пустое, введите привязки для начала и конца: ^(.*)$.

    31.08.2011

    4

    Замена "" на "George" (.* соответствует "")

    и

    "This is a start" == "This is a start" + "" 
    

    Итак, регулярное выражение соответствует "This is a start" и заменяет его на "George", и теперь его «курсор» находится в конце строки, где он снова пытается сопоставить оставшуюся строку ("") с шаблоном. У него есть совпадение, поэтому он добавляет второе "George". Я не знаю, правильно это или нет.

    Я добавлю, что движок Javascript, кажется, делает то же самое (проверено здесь: https://www.regular-expressions.info/javascriptexample.html ) в IE и Chrome.

    31.08.2011
  • Я считаю, что это на самом деле начальная позиция, вызывающая проблему. Это решено, если вы измените регулярное выражение на ^(.*) 27.02.2020
  • Новые материалы

    Как создать диаграмму градиентной кисти с помощью D3.js
    Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

    Лицензии с открытым исходным кодом: руководство для разработчиков и создателей
    В динамичном мире разработки программного обеспечения открытый исходный код стал мощной парадигмой, способствующей сотрудничеству, инновациям и прогрессу, движимому сообществом. В основе..

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

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

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


    Для любых предложений по сайту: [email protected]