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

时间:2017-03-31 16:51:43

标签: google-bigquery

我有以下字符串:

brasília

我需要转换为:

brasilia

带着'口音!

如何在BigQuery上进行操作?

谢谢!

4 个答案:

答案 0 :(得分: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   

输出

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   
  

更新

下面是如何将此逻辑打包到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 

答案 1 :(得分:4)

值得一提的是,您所要求的是unicode text normalization的简化案例。许多语言在其标准库中具有此功能(例如,Java)。一个好的方法是插入你的文本BigQuery已经规范化。如果这不起作用 - 例如,因为你需要保留原始文本而你又担心点击BigQuery's row size limit - 那么你需要动态地进行规范化在您的查询中。

某些数据库具有各种完整性的Unicode规范化实现(例如,PostgreSQL's unaccent methodPrestoDB's normalize method),以便在查询中使用。不幸的是,BigQuery不是其中之一。在撰写本文时,BigQuery中没有文本规范化功能。这个答案的实现有点像#34;滚动你自己的unaccent。"当BigQuery发布官方功能时,每个人都应该使用它!

假设您需要在查询中进行规范化(并且Google尚未提供此功能),这些都是合理的选择。

方法1:使用NORMALIZE

Google现在推出NORMALIZE功能。 (感谢@WillianFuks对标记的评论!)现在这是文本规范化的明显选择。例如:

  
SELECT REGEXP_REPLACE(NORMALIZE(text), r"\pM", '') FROM yourtable;

有一个简短的解释,说明这是如何工作的以及为什么在评论中需要调用REGEXP_REPLACE

我已将其他方法留作参考。

方法2:在内容

上使用REGEXP_REPLACEREPLACE

我使用REGEXP_REPLACE在旧版SQL中实现了仅小写的文本规范化案例。 (标准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);

  
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);

平均而言,REGEXP_REPLACE实施约2.9s;基于数组的实现在大约12.5秒内运行。

方法3:在搜索模式

上使用REGEXP_REPLACE

是什么让我回答这个问题我的搜索用例。对于这个用例,我可以规范化我的语料库文本,使其看起来更像我的查询,或者我可以"反规范化"我的查询,使它看起来更像我的文字。以上描述了第一种方法的实现。这描述了第二种实现。

搜索单个单词时,可以使用REGEXP_MATCH匹配功能,只使用以下模式更新查询:

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)

所以查询"你好"看起来像这样,作为一个正则表达式:

r"h[eèéêëēėę][lł][lł][oôöòóøōõ]"

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

答案 2 :(得分:1)

您可以拨打REPLACE()或REGEXP_REPLACE()。您可以在Remove accents/diacritics in a string in JavaScript找到一些正则表达式。

或者,你可以使用javascript UDF,但我希望它会慢一些。

答案 3 :(得分:1)

我喜欢this answer的解释。您可以使用:

REGEXP_REPLACE(NORMALIZE(text, NFD), r'\pM', '')

作为一个简单的例子:

WITH data AS(
  SELECT 'brasília / paçoca' AS text
)

SELECT
  REGEXP_REPLACE(NORMALIZE(text, NFD), r'\pM', '') RemovedDiacritics
FROM data

巴西利亚/ pacoca

更新

使用新的字符串函数Translate,可以轻松得多:

WITH data AS(
  SELECT 'brasília / paçoca' AS text
)

SELECT
  translate(text, "ŠŽšžŸÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖÙÚÛÜÝàáâãäåçèéêëìíîïðñòóôõöùúûüýÿ", "SZszYAAAAAACEEEEIIIIDNOOOOOUUUUYaaaaaaceeeeiiiidnooooouuuuyy") as RemovedDiacritics
FROM data

巴西利亚/ pacoca