Безопасное приведение соответствия регулярному выражению из REGEXP_REPLACE - PullRequest
1 голос
/ 31 октября 2019

У меня есть таблица с некоторыми кодовыми точками (например, &), которую я хочу вырезать из текстового значения в BigQuery.

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

Если я попытаюсь:

WITH items as (SELECT "Test & " as item)
SELECT
  CODE_POINTS_TO_STRING([SAFE_CAST(REGEXP_EXTRACT(item, r"&#([0-9]{2})") AS INT64)]) as test_replace
FROM items

Это выдаст желаемый вывод для записи

[
  {
    "test_replace": "&"
  }
]

Если я попытаюсь:

WITH items as (SELECT "Test & " as item)
SELECT
  REGEXP_REPLACE(
    item, 
    r"&#([0-9]{2});", 
    CODE_POINTS_TO_STRING([SAFE_CAST("\\1" as INT64)])
    ) as full_replace
FROM items

Это приведет к нулевому выводу

[
  {
    "full_replace": null
  }
]

Однако, если я жестко закодирую значение в:

WITH items as (SELECT "Test & " as item)
SELECT
  REGEXP_REPLACE(
    item, 
    r"&#([0-9]{2});", 
    CODE_POINTS_TO_STRING([SAFE_CAST("38" as INT64)])
    ) as full_replace
FROM items

Это работает.

[
  {
    "full_replace": "Test & "
]

Я знаю, что регулярное выражение правильно оценивается, как будто я пытаюсь:

WITH items as (SELECT "Test & " as item)
SELECT
  REGEXP_REPLACE(
    item, 
    r"&#([0-9]{2});", 
    CONCAT("\\1", "test")
  ) as part_replace
FROM ITEMS

Это вернет:

[
  {
    "part_replace": "Test 38test "
  }
]

Поэтому мой вопрос, как мне получить функцию SAFE_CAST () дляоценить соответствие регулярному выражению (кажется, что оно вычисляет строковый литерал).

1 Ответ

1 голос
/ 31 октября 2019

У меня есть таблица с некоторыми кодовыми точками (например, &), которую я хочу вырезать из текстового значения в BigQuery.

Попробуйте подход, как в примере ниже

#standardSQL
CREATE TEMP FUNCTION multiReplace(item STRING, arr ARRAY<STRUCT<x STRING, y STRING>>)
RETURNS STRING
LANGUAGE js AS """
  for (i = 0; i < arr.length; i++) {
    item = item.replace(arr[i].x, arr[i].y)
  };
  return item;
""";
WITH items AS (
  SELECT "Test &#38; abc &#39; xyz" AS item UNION ALL
  SELECT "abc xyz"
)
SELECT item, multiReplace(item, points) full_replace
FROM (
  SELECT 
    item,
    ARRAY(
      SELECT AS STRUCT val, CODE_POINTS_TO_STRING([SAFE_CAST(SUBSTR(val, -3, 2) AS INT64)]) point
      FROM UNNEST(REGEXP_EXTRACT_ALL(item, r'(&#[0-9]{2};)')) val
    ) points
  FROM items
)

с результатом

Row item                        full_replace     
1   Test &#38; abc &#39; xyz    Test & abc ' xyz     
2   abc xyz                     abc xyz     

Опция 2

Покасамый простой способ приблизиться выше - это

#standardSQL
CREATE TEMP FUNCTION multiReplace(item STRING)
RETURNS STRING
LANGUAGE js AS """
  var decodeHtmlEntity = function(str) {
    return str.replace(/&#([0-9]{2});/g, function(match, dec) {
      return String.fromCharCode(dec);
    });
  };
  return decodeHtmlEntity(item);
""";
WITH items AS (
  SELECT "Test &#38; abc &#39; xyz" AS item UNION ALL
  SELECT "abc xyz"
)
SELECT item, multiReplace(item) full_replace
FROM items   

с тем же выводом

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...