BigQuery:将重音字符转换为简单的ascii等价物

Fel*_*rlo 4 google-bigquery

我有以下字符串:

brasília
Run Code Online (Sandbox Code Playgroud)

我需要转换为:

brasilia
Run Code Online (Sandbox Code Playgroud)

带着'口音!

我怎么能在BigQuery上做?

谢谢!

Mur*_*rta 7

我喜欢这个答案的解释。您可以使用:

\n
REGEXP_REPLACE(NORMALIZE(text, NFD), r\'\\pM\', \'\')\n
Run Code Online (Sandbox Code Playgroud)\n

举个简单的例子:

\n
WITH data AS(\n  SELECT \'bras\xc3\xadlia / pa\xc3\xa7oca\' AS text\n)\n\nSELECT\n  REGEXP_REPLACE(NORMALIZE(text, NFD), r\'\\pM\', \'\') RemovedDiacritics\nFROM data\n
Run Code Online (Sandbox Code Playgroud)\n
\n

巴西利亚/帕科卡

\n
\n

更新

\n

使用新的字符串函数Translate,操作起来要简单得多:

\n
WITH data AS(\n  SELECT \'bras\xc3\xadlia / pa\xc3\xa7oca\' AS text\n)\n\nSELECT\n  translate(text, "\xc5\xa0\xc5\xbd\xc5\xa1\xc5\xbe\xc5\xb8\xc3\x80\xc3\x81\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x87\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3\x90\xc3\x91\xc3\x92\xc3\x93\xc3\x94\xc3\x95\xc3\x96\xc3\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa7\xc3\xa8\xc3\xa9\xc3\xaa\xc3\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf\xc3\xb0\xc3\xb1\xc3\xb2\xc3\xb3\xc3\xb4\xc3\xb5\xc3\xb6\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3\xbd\xc3\xbf", "SZszYAAAAAACEEEEIIIIDNOOOOOUUUUYaaaaaaceeeeiiiidnooooouuuuyy") as RemovedDiacritics\nFROM data\n
Run Code Online (Sandbox Code Playgroud)\n
\n

巴西利亚/帕科卡

\n
\n

  • “translate”现在应该成为公认的答案。 (2认同)

Mik*_*ant 5

请尝试以下快速简单的选项:

#standardSQL
WITH lookups AS (
  SELECT 
  'ç,æ,œ,á,é,í,ó,ú,à,è,ì,ò,ù,ä,ë,ï,ö,ü,ÿ,â,ê,î,ô,û,å,ø,Ø,Å,Á,À,Â,Ä,È,É,Ê,Ë,Í,Î,Ï,Ì,Ò,Ó,Ô,Ö,Ú,Ù,Û,Ü,Ÿ,Ç,Æ,Œ,ñ' AS accents,
  'c,ae,oe,a,e,i,o,u,a,e,i,o,u,a,e,i,o,u,y,a,e,i,o,u,a,o,O,A,A,A,A,A,E,E,E,E,I,I,I,I,O,O,O,O,U,U,U,U,Y,C,AE,OE,n' AS latins
),
pairs AS (
  SELECT accent, latin FROM lookups, 
    UNNEST(SPLIT(accents)) AS accent WITH OFFSET AS p1, 
    UNNEST(SPLIT(latins)) AS latin WITH OFFSET AS p2
  WHERE p1 = p2
),
yourTableWithWords AS (
  SELECT word FROM UNNEST(
        SPLIT('brasília,ångström,aperçu,barège, beau idéal, belle époque, béguin, bête noire, bêtise, Bichon Frisé, blasé, blessèd, bobèche, boîte, bombé, Bön, Boötes, boutonnière, bric-à-brac, Brontë Beyoncé,El Niño')
    ) AS word
)
SELECT 
  word AS word_with_accent, 
  (SELECT STRING_AGG(IFNULL(latin, char), '')
    FROM UNNEST(SPLIT(word, '')) char
    LEFT JOIN pairs
    ON char = accent) AS word_without_accent
FROM yourTableWithWords   
Run Code Online (Sandbox Code Playgroud)

输出是

word_with_accent word_without_accent     
blessèd         blessed  
El Niño         El Nino  
belle époque    belle epoque     
boîte           boite    
Boötes          Bootes   
blasé           blase    
ångström        angstrom     
bobèche         bobeche  
barège          barege   
bric-à-brac     bric-a-brac  
bête noire      bete noire   
Bichon Frisé    Bichon Frise     
Brontë Beyoncé  Bronte Beyonce   
bêtise          betise   
beau idéal      beau ideal   
bombé           bombe    
brasília        brasilia     
boutonnière     boutonniere  
aperçu          apercu   
béguin          beguin   
Bön             Bon   
Run Code Online (Sandbox Code Playgroud)

UPDATE

下面是如何将此逻辑打包到SQL UDF中 - 因此accent2latin(word)可以调用以创建"魔术"

#standardSQL
CREATE TEMP FUNCTION accent2latin(word STRING) AS
((
  WITH lookups AS (
    SELECT 
    'ç,æ,œ,á,é,í,ó,ú,à,è,ì,ò,ù,ä,ë,ï,ö,ü,ÿ,â,ê,î,ô,û,å,ø,Ø,Å,Á,À,Â,Ä,È,É,Ê,Ë,Í,Î,Ï,Ì,Ò,Ó,Ô,Ö,Ú,Ù,Û,Ü,Ÿ,Ç,Æ,Œ,ñ' AS accents,
    'c,ae,oe,a,e,i,o,u,a,e,i,o,u,a,e,i,o,u,y,a,e,i,o,u,a,o,O,A,A,A,A,A,E,E,E,E,I,I,I,I,O,O,O,O,U,U,U,U,Y,C,AE,OE,n' AS latins
  ),
  pairs AS (
    SELECT accent, latin FROM lookups, 
      UNNEST(SPLIT(accents)) AS accent WITH OFFSET AS p1, 
      UNNEST(SPLIT(latins)) AS latin WITH OFFSET AS p2
    WHERE p1 = p2
  )
  SELECT STRING_AGG(IFNULL(latin, char), '')
  FROM UNNEST(SPLIT(word, '')) char
  LEFT JOIN pairs
  ON char = accent
));

WITH yourTableWithWords AS (
  SELECT word FROM UNNEST(
        SPLIT('brasília,ångström,aperçu,barège, beau idéal, belle époque, béguin, bête noire, bêtise, Bichon Frisé, blasé, blessèd, bobèche, boîte, bombé, Bön, Boötes, boutonnière, bric-à-brac, Brontë Beyoncé,El Niño')
    ) AS word
)
SELECT 
  word AS word_with_accent, 
  accent2latin(word) AS word_without_accent
FROM yourTableWithWords 
Run Code Online (Sandbox Code Playgroud)


sig*_*ned 5

值得一提的是,您要求的是unicode text normalization的简化案例。许多语言在它们的标准库(例如Java)中有一个函数。一种好方法是插入已规范化的 BigQuery 文本。如果这不起作用 - 例如,因为您需要保留原始文本并且您担心达到BigQuery 的行大小限制- 那么您需要在查询中动态进行规范化。

一些数据库具有各种完整性的 Unicode 规范化实现(例如,PostgreSQL 的unaccent方法PrestoDB 的 normalize 方法)用于查询。不幸的是,BigQuery 不是其中之一。在撰写本文时,BigQuery 中没有文本规范化功能。这个答案的实现有点像“滚动你自己的口音”。当 BigQuery 发布官方功能时,每个人都应该改用它!

假设您需要在查询中进行规范化(而且 Google 还没有为此提供功能),这些是一些合理的选择。

方法一:使用 NORMALIZE

谷歌现在已经推出了一个NORMALIZE功能。(感谢@WillianFuks 在标记评论中!)这现在是文本规范化的明显选择。例如:

SELECT REGEXP_REPLACE(NORMALIZE(text, NFD), r"\pM", '') FROM yourtable;
Run Code Online (Sandbox Code Playgroud)

在评论中简要说明了这是如何工作的以及为什么REGEXP_REPLACE需要调用。

我留下了其他方法供参考。

方法 2:在内容上使用REGEXP_REPLACEREPLACE

我使用REGEXP_REPLACE. (标准 SQL 中的模拟是不言而喻的。)我使用以下查询在一个 28M 行的大表中对平均长度约为 1K 的文本字段进行了一些测试:

SELECT id, text FROM
  (SELECT 
    id,
    CASE
    WHEN REGEXP_CONTAINS(LOWER(text), r"[àáâäåæçèéêëìíîïòóôöøùúûüÿœ]") THEN
      REGEXP_REPLACE(
        REGEXP_REPLACE(
          REGEXP_REPLACE(
            REGEXP_REPLACE(
              REGEXP_REPLACE(
                REPLACE(REPLACE(REPLACE(REPLACE(LOWER(text), 'œ', 'ce'), 'ÿ', 'y'), 'ç', 'c'), 'æ', 'ae'),
              r"[ùúûü]", 'u'),
            r"[òóôöø]", 'o'),
          r"[ìíîï]", 'i'),
        r"[èéêë]", 'e'),
      r"[àáâäå]", 'a')
    ELSE
      LOWER(text)
    END AS text
  FROM
   yourtable ORDER BY id LIMIT 10);
Run Code Online (Sandbox Code Playgroud)

相对:

WITH lookups AS (
  SELECT 
  'ç,æ,œ,á,é,í,ó,ú,à,è,ì,ò,ù,ä,ë,ï,ö,ü,ÿ,â,ê,î,ô,û,å,ø,ñ' AS accents,
  'c,ae,oe,a,e,i,o,u,a,e,i,o,u,a,e,i,o,u,y,a,e,i,o,u,a,o,n' AS latins
),
pairs AS (
  SELECT accent, latin FROM lookups, 
    UNNEST(SPLIT(accents)) AS accent WITH OFFSET AS p1, 
    UNNEST(SPLIT(latins)) AS latin WITH OFFSET AS p2
  WHERE p1 = p2
)
SELECT foo FROM (
  SELECT 
    id,
    (SELECT STRING_AGG(IFNULL(latin, char), '') AS foo FROM UNNEST(SPLIT(LOWER(text), '')) char LEFT JOIN pairs ON char=accent) AS foo
  FROM
  yourtable ORDER BY id LIMIT 10);
Run Code Online (Sandbox Code Playgroud)

平均而言,REGEXP_REPLACE实施运行时间约为 2.9 秒;基于数组的实现运行时间约为 12.5 秒。

方法 3:REGEXP_REPLACE在搜索模式上使用

让我想到这个问题的是一个搜索用例。对于这个用例,我可以规范化我的语料库文本,使其看起来更像我的查询,或者我可以“非规范化”我的查询,使其看起来更像我的文本。以上描述了第一种方法的实现。这描述了第二个的实现。

搜索单个单词时,可以使用REGEXP_MATCHmatch 函数并仅使用以下模式更新查询:

a -> [aàáaâäãå?]
e -> [eèéêë???]
i -> [iîïí??ì]
o -> [oôöòóø?õ]
u -> [uûüùú?]
y -> [yÿ]
s -> [sß?š]
l -> [l?]
z -> [zž??]
c -> [cç??]
n -> [nñ?]
æ -> (?:æ|ae)
œ -> (?:œ|ce)
Run Code Online (Sandbox Code Playgroud)

所以查询“hello”看起来像这样,作为一个正则表达式:

r"h[eèéêë???][l?][l?][oôöòóø?õ]"
Run Code Online (Sandbox Code Playgroud)

在任何语言中,将单词转换为这个正则表达式应该是相当简单的。这不是已发布问题的解决方案——“如何删除 BigQuery 中的重音?” -- 而是相关用例的解决方案,它可能会将人们(像我一样!)带到此页面。

  • 我想知道规范化方法如何解决这个问题;我尝试使用新的 [normalize](https://cloud.google.com/bigquery/docs/reference/standard-sql/functions-and-operators#normalize) 函数,但没有用。你知道怎么做吗? (2认同)