Поиск n-го вхождения шаблона в строке в SQL (Presto)

Я пишу запрос в Presto SQL с помощью функции regexp_extract

У меня есть строка, которая может выглядеть как в следующих примерах:

      '1A2B2C3D3E'
'1A1B2C2D3E'
'1A2B1C2D2E'

Я пытаюсь найти, например, второе вхождение 1 [AE].

Если я попробую

      regexp_extract(col, '(1[A-E])(1[A-E])', 2)

Это будет работать для второго примера (и первого, поскольку он ничего не возвращает, поскольку второго вхождения нет). Однако в третьем примере это не получится. Он ничего не возвращает. Я знаю , что это потому , что мое регулярное выражение ищет 1 [AE] , а затем непосредственно на другие 1 [AE].

Итак, я попробовал

      regexp_extract(col, '(1[A-E])(.*)(1[A-E])', 3)

Но это тоже не работает. Я не уверен, как я могу объяснить тот факт, что у меня может быть 1A1B2C или 1A2B1C, чтобы найти эту вторую 1. Любая помощь?

2 ответа

Ваш второй шаблон действительно работает в последней версии Trino ( ранее известной как Presto SQL):

      WITH t(col) AS (
  VALUES 
    '1A2B2C3D3E', 
    '1A1B2C2D3E',
    '1A2B1C2D2E')
SELECT regexp_extract(col, '(1[A-E])(.*)(1[A-E])', 3)
FROM t
       _col0
-------
 NULL
 1B
 1C
(3 rows)

Как отмечали другие, вам не нужны группы захвата для первого совпадения или для, и вы должны использовать ленивый квантификатор, чтобы избежать .* с нетерпением сопоставляет все символы между первым и последним вхождением:

      WITH t(col) AS (
    VALUES 
        '1A2B2C3D3E', 
        '1A1B2C2D3E',
        '1A2B1C2D2E', 
        '1A2B1C2D1E') 
SELECT regexp_extract(col, '1[A-E].*?(1[A-E])', 1)
FROM t
       _col0
-------
 NULL
 1B
 1C
 1C
(4 rows)

Вторая группа захвата не нужна (.*) чтобы сохранить 2 группы захвата в результате, и вы можете при желании сопоставить разрешенные символы между ними.

Из того, что я прочитал на этой странице, вы также можете рассмотреть возможность использования regexp_extract_all чтобы получить все совпадения, как regexp_extract возвращает первое совпадение.

Поскольку данные примера состоят из цифры, за которой следует символ AE, вы можете исключить соответствие 1 из класса символов, чтобы предотвратить избыточное соответствие и возврат.

      (1[A-E])[02-9A-E]*(1[A-E])

Демо Regex

Если использование одной группы захвата для получения второго значения тоже нормально, вы можете использовать

      1[A-E][02-9A-E]*(1[A-E])

Демо Regex

Другие вопросы по тегам