【问题标题】:BigQuery REGEXP_MATCH and accents : boundary wildcard fails?BigQuery REGEXP_MATCH 和口音:边界通配符失败?
【发布时间】:2014-04-05 07:21:18
【问题描述】:

在 GAS 中,我可以正确地将重音与具有边界字符的正则表达式匹配,例如 \bà\b。字符 à 仅在它是一个单独的单词时才匹配。这适用于 GAS:

function test_regExp() {
  var str = "la séance est à Paris";
  var RegExp = "\\bà\\b";
  var PatReg= new RegExp( RegExp);
  var found=PatReg.exec(str);
  if (found) {
    Logger.log( [str.substring(0,found.index),found[0],str.substring(found[0].length+found.index)] );
  } else Logger.log("oops! Did not match");

在 BigQuery 中,如果边界字符位于重音符号旁边,则模式不匹配。 \bséance\b 匹配降神会:

SELECT [row],etext,ftext FROM [hcd.hdctextx] WHERE (REGEXP_MATCH(ftext,"\\bséance\\b") ) LIMIT 100;

\bà\b 不匹配 à 作为单词:

SELECT [row],etext,ftext FROM [hcd.hdctextx] WHERE (REGEXP_MATCH(ftext,"\\bà\\b") ) LIMIT 100;

我假设 BigQuery 与 GAS 不同,它在边界字符集中包含重音符号。所以 \bséance\b 有效,因为 é 可以作为该配置中的边界正常工作。 \bà\b 或 \bétranger\b 或 \bmarché\b 不起作用,因为重音 + \b 被解释为 \b\b,它从不匹配任何内容。 (好吧,我在这里抓住了稻草,因为我找不到更好的解释......除了一个错误。)

我不认为这是一个 unicode 问题,因为它只会出现在边界位置。

因此,目前无法在这些特定的重音配置中使用边界。

有没有办法在 BigQuery 或其他修复中设置语言环境?

解决方法:用 (?:[^a-zA-Zéàïëâê]) 等替换 \b。

谢谢!

【问题讨论】:

  • 另一个发现:模式 "(?:\\PL)à" 在 BQ 中有效,但在 GAS 中无效。两者都应该使用相同的 RE 实现。可能是这个问题纯粹是一个字符集问题,但它看起来像是一个错误的 RE 实现......在一个或另一个或两者上。

标签: regex google-apps-script google-bigquery


【解决方案1】:

BigQuery 的行为对于 RE2 syntax documentation 是正确的。 (不足为奇,因为 BigQuery 使用 RE2 来实现正则表达式。)

RE2 的角色类别是:

\b = at word boundary (\w on one side and \W, \A, or \z on the other)
\w = word characters (≡ [0-9A-Za-z_])
\W = not word characters (≡ [^0-9A-Za-z_])
\A = beginning of text
\z = end of text

换句话说,您只能使用 \b 来匹配非重音字符的边界。不过,RE2 对 Unicode 字符有很多支持,因此您很可能可以使用 \pL 之类的东西制作替代正则表达式。

我不确定为什么 Google Apps 脚本不遵循 RE2 规范,但我会跟进该团队以了解发生了什么。

【讨论】:

    【解决方案2】:

    看看这个:

    SElect Regexp_extract(StringToParse,r'\b?(à)\b?') as Extract,
     Regexp_match(StringToParse,r'\b?(à)\b?') as match,
    FROM
    (SELECT 'la séance est à Paris' as StringToParse)
    

    希望对你有帮助

    【讨论】:

    • 有趣的想法。到目前为止,我发现 r'\b?(à)\b?'在 BQ 中有效(r'...' 语法在 GAS 中无效)。并且 '\\b(à)\\b' (无量词)匹配 GAS 中的相同内容(GAS 不接受 \b 上的量词)。我的应用程序在 GAS 和 BQ 中执行相同的搜索,但我不能在两者中使用相同的 RE 表达式——即使文档说它们使用相同的实现,RE 的工作方式也不相同!谢谢你的帮助! (我仍在研究系统的解决方法。) PS:这种差异似乎会影响其他字符类,例如 \PL 或 \W。
    • 让我后退:r'\b?(à)\b?'在 BQ 中不起作用 因为它也会检索 Voilà,因为 \b?可以忽略。所以它会找到所有的 à,而不是 à 作为一个单词,这就是 \b...\b 表达式可以做的事情。 (您的建议仍然很有帮助,因为它鼓励我探索其他同义词。谢谢!)
    【解决方案3】:

    答案是:在 BQ 中不要使用带有重音符号的 \b;重写正则表达式:

    frenRegExp = frenRegExp.replace(/\\b/g, "(?:[- .,;!?()]|$|^)");      
    frenRegExp = frenRegExp.replace(/\\w/g, "(?:[A-Za-zÀàÂâÄ䯿ÇçÈèÉéÊêËëÎîÏïÔôÙùÛûÜüñ])"); 
    frenRegExp = frenRegExp.replace(/\\W/g, "(?:[^A-Za-zÀàÂâÄ䯿ÇçÈèÉéÊêËëÎîÏïÔôÙùÛûÜüñ])");  
    

    此外,尽管 GAS 规范将 RE2 作为其重新引擎(哎呀!我真的不知道它使用什么,因为它不会像 BQ 一样从 \w 中排除重音字符),但它只是部分实现。例如 \pL 不匹配一个字母。

    以下是一些适用于应用程序脚本的测试代码,但如果没有替换,则不适用于 BQ。

    ////////////////////// TEST ///////////////////
    
    function test_regExp() {
      var str = " Voilà la séance générale qui est à Paris";
      var RegExpString ="\\bs\\w+an\\w*"
      Logger.log(RegExpString);
      var RegExpCompiled= new RegExp( RegExpString,"i");
      Logger.log(RegExpCompiled.source); 
      var found=RegExpCompiled.exec(str);
      if (found) {
        Logger.log("|"+found[0]+"|")
        Logger.log( [str.substring(0,found.index),found[0],str.substring(found[0].length+found.index)] );
      } else Logger.log("Oops: not found");
    
    }
    

    输出:

    [16-02-09 22:15:59:659 PST] \bs\w+anc\w*
    [16-02-09 22:15:59:660 PST] \bs\w+an\w*
    [16-02-09 22:15:59:660 PST] |séance|
    [16-02-09 22:15:59:661 PST] [ Voilà la , séance,  générale qui est à Paris]
    

    【讨论】:

    • 很好的解释,谢谢!您将如何表达功能请求以转发给团队?
    • 我认为这是一个错误,真的,在 \b 的情况下。在 GAS 的情况下,这是一个不完整的实现。我将尝试将其记录为错误(对我来说是第一次):\b + 重音字符与 BQ 中应有的位置不匹配。就是这样。
    猜你喜欢
    • 2020-06-05
    • 2016-11-29
    • 2012-08-14
    • 1970-01-01
    • 2017-09-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多