Другой, немного другой подход (BigQuery Standard SQL)
#standardSQL
CREATE TEMP FUNCTION OTRANSLATE(text STRING, from_string STRING, to_string STRING) AS ((
SELECT STRING_AGG(IFNULL(y, a), '' ORDER BY pos)
FROM UNNEST(SPLIT(text, '')) a WITH OFFSET pos
LEFT JOIN (
SELECT x, y
FROM UNNEST(SPLIT(from_string, '')) x WITH OFFSET
JOIN UNNEST(SPLIT(to_string, '')) y WITH OFFSET
USING(OFFSET)
)
ON a = x
));
WITH `project.dataset.table` AS (
SELECT 'hello world' AS text UNION ALL
SELECT 'elliott'
)
SELECT text, OTRANSLATE(text, 'ehlo', 'EHLO') as new_text
FROM `project.dataset.table`
с выходом
Row text new_text
1 hello world HELLO wOrLd
2 elliott ELLiOtt
Примечание: вышеприведенная версия предполагает, что строки от и до равны по длине и без повторяющихся символов в строке
Обновление для отслеживания "расширенных ожиданий" для версии этой функции в BigQuery
#standardSQL
CREATE TEMP FUNCTION OTRANSLATE(text STRING, from_string STRING, to_string STRING) AS ((
SELECT STRING_AGG(IFNULL(y, a), '' ORDER BY pos)
FROM UNNEST(SPLIT(text, '')) a WITH OFFSET pos
LEFT JOIN (
SELECT x, ARRAY_AGG(IFNULL(y, '') ORDER BY OFFSET LIMIT 1)[OFFSET(0)] y
FROM UNNEST(SPLIT(from_string, '')) x WITH OFFSET
LEFT JOIN UNNEST(SPLIT(to_string, '')) y WITH OFFSET
USING(OFFSET)
GROUP BY x
)
ON a = x
));
SELECT -- text, OTRANSLATE(text, 'ehlo', 'EHLO') as new_text
OTRANSLATE("hello world", "", "EHLO") AS empty_from, -- 'hello world'
OTRANSLATE("hello world", "hello world1", "EHLO") AS larger_from_than_source, -- 'EHLLL'
OTRANSLATE("hello world", "ehlo", "EHLO") AS equal_size_from_to, -- 'HELLO wOrLd'
OTRANSLATE("hello world", "ehlo", "EH") AS larger_size_from, -- 'HE wrd'
OTRANSLATE("hello world", "ehlo", "EHLOPQ") AS larger_size_to, -- 'hello world'
OTRANSLATE("hello world", "ehlo", "") AS empty_to; -- 'wrd'
с результатом
Row empty_from larger_from_than_source equal_size_from_to larger_size_from larger_size_to empty_to
1 hello world EHLLL HELLO wOrLd HE wrd HELLO wOrLd wrd
.
Примечание: версия этой функции Teradata является рекурсивной, поэтому текущая реализация не является точной реализацией OTRANSLATE Teradata
Замечания по использованию (из документации teradata)
Если первый символ в from_string встречается в source_string, все его вхождения заменяются первым символом в to_string. Это повторяется для всех символов в from_string и для всех символов в from_string. Замена выполняется посимвольно, то есть замена второго символа выполняется в строке, полученной в результате замены первого символа.
Это может быть легко реализовано с помощью JS UDF, что тривиально, я думаю, что я не иду в этом направлении: o)