Почему кажется, что регулярное выражение OR чувствительно к порядку? [Дубликат]

Большинство ответов здесь не могут объяснить, какова фактическая проблема с разрезанием. Они объясняют только доброкачественные случаи нарезки, а не предательские. Предположим, как и другие ответы, что вы имеете дело с двумя классами A и B, где B получает (публично) из A.

В этой ситуации C ++ позволяет вам передать экземпляр оператора B в A, а также в конструктор копирования. Это работает, потому что экземпляр B может быть преобразован в const A&, а именно, какие операторы присваивания и конструкторы-копии ожидают, что их аргументы будут.

Доброкачественный случай

B b;
A a = b;

Ничего плохого в этом нет - вы попросили экземпляр A, который является копией B, и это именно то, что вы получаете. Конечно, a не будет содержать некоторых членов b, но как это сделать? В конце концов, это A, а не B, поэтому даже не слышал об этих членах, не говоря уже о возможности их хранения.

вероломный случай

B b1;
B b2;
A& a_ref = b2;
a_ref = b1;
//b2 now contains a mixture of b1 and b2!

Вы можете подумать, что b2 будет копией b1 впоследствии. Но, увы, это не так! Если вы проверите его, вы обнаружите, что b2 - это франкенштейновское существо, сделанное из некоторых кусков b1 (куски, которые B наследует от A), и некоторые фрагменты b2 (куски что только B содержит). Ой!

Что случилось? Ну, C ++ по умолчанию не обрабатывает операторы присваивания как virtual. Таким образом, строка a_ref = b1 вызовет оператор присваивания A, а не номер B. Это связано с тем, что для не виртуальных функций объявленный тип (который является A&) определяет, какая функция вызывается, в отличие от фактического типа (который был бы B, поскольку a_ref ссылается на экземпляр B ). Теперь оператор присваивания A явно знает только о членах, объявленных в A, поэтому он будет копировать только те, оставляя члены, добавленные в B без изменений.

Решение

Присвоение только части объекта обычно имеет мало смысла, но, к сожалению, C ++ не предусматривает встроенного способа запретить это. Вы можете, однако, бросить свои собственные. Первый шаг - сделать оператор присваивания виртуальным . Это гарантирует, что он всегда является оператором присваивания фактического типа, который вызывается, а не объявленным типом. Второй шаг - использовать dynamic_cast, чтобы убедиться, что назначенный объект имеет совместимый тип. Третий шаг - выполнить фактическое присвоение в члене (protected!) assign(), так как B assign(), вероятно, захочет использовать A 's assign() для копирования A членов .

class A {
public:
  virtual A& operator= (const A& a) {
    assign(a);
    return *this;
  }

protected:
  void assign(const A& a) {
    // copy members of A from a to this
  }
};

class B : public A {
public:
  virtual B& operator= (const A& a) {
    if (const B* b = dynamic_cast<const B*>(&a))
      assign(*b);
    else
      throw bad_assignment();
    return *this;
  }

protected:
  void assign(const B& b) {
    A::assign(b); // Let A's assign() copy members of A from b to this
    // copy members of B from b to this
  }
};

Обратите внимание, что для чистого удобства B operator= ковариантно переопределяет возвращаемый тип, поскольку он знает, что он возвращает экземпляр B.

3
задан Athari 2 August 2013 в 14:07
поделиться

1 ответ

Механизм регулярных выражений пытается сопоставить альтернативы в том порядке, в котором они указаны. Поэтому, когда шаблон (foo|foobar)&? сразу же foo, он продолжает поиск совпадений. Следующий бит входной строки - bar& b, который не может быть сопоставлен.

Другими словами, поскольку foo является частью foobar, нет способа (foo|foobar) когда-либо соответствовать foobar ], так как он всегда будет соответствовать foo.

Иногда это может быть очень полезным трюком. Шаблон (o|a|(\w)) позволит вам захватить \w и a или o по-другому:

Regex.Replace("a foobar& b", "(o|a|(\\w))", "$2") // fbr& b
4
ответ дан p.s.w.g 20 August 2018 в 20:16
поделиться
  • 1
    Почему не регулярное выражение жадно? Я думал, что он должен соответствовать самой длинной строке, которую он может сопоставить. – Athari 2 August 2013 в 14:13
  • 2
    @Athari жадность применяется к квантификаторам, а не к чередованиям. – p.s.w.g 2 August 2013 в 14:14
  • 3
    Есть ли способ заставить жадность к изменениям, или мне нужно сортировать изменения в обратном алфавитном порядке? – Athari 2 August 2013 в 14:16
  • 4
    @Athari Алфавитный порядок не имеет значения. Сначала чередование должно сортироваться по шаблону wideest , например. foobar шире foo, потому что любая строка, которая соответствует foo, также будет соответствовать foobar (конечно, foo(bar)? здесь более разумно). Если вы не пытаетесь использовать трюк, описанный в моем обновленном ответе. – p.s.w.g 2 August 2013 в 14:22
  • 5
    В моем реальном случае список довольно длинный, поэтому сделать регулярное выражение сложнее не стоит. Я думаю, это предложение решает мою проблему, поскольку мне нужно сопоставить отдельные слова. – Athari 2 August 2013 в 14:27
Другие вопросы по тегам:

Похожие вопросы: