语言标签的正则表达式(由 BCP47 定义)

发布于 2024-11-28 23:40:37 字数 321 浏览 0 评论 0 原文

我需要一个由 语言标记 的正则表达式.org/rfc/bcp/bcp47.txt">BCP 47。

我知道完整的 BNF 语法可以在 http://www.rfc-editor.org/rfc/ bcp/bcp47.txt 并且我可以用它来编写我自己的,但希望已经有一个了。

I need a regular expression for a language tag as defined by BCP 47.

I know that the full BNF syntax is available at http://www.rfc-editor.org/rfc/bcp/bcp47.txt and that I could use it to write my own, but hopefully there is one already out there.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

煮茶煮酒煮时光 2024-12-05 23:40:37

看起来像这样:

^((?<grandfathered>(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|
i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|
cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?<language>
([A-Za-z]{2,3}(-(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})
(-(?<script>[A-Za-z]{4}))?(-(?<region>[A-Za-z]{2}|[0-9]{3}))?(-(?<variant>[A-Za-z0-9]{5,8}
|[0-9][A-Za-z0-9]{3}))*(-(?<extension>[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*
(-(?<privateUse>x(-[A-Za-z0-9]{1,8})+))?)|(?<privateUse>x(-[A-Za-z0-9]{1,8})+))$

这是生成它的代码(用 C# 编写):

var regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)";
var irregular = "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)";
var grandfathered = "(?<grandfathered>" + irregular + "|" + regular + ")";
var privateUse = "(?<privateUse>x(-[A-Za-z0-9]{1,8})+)";
var singleton = "[0-9A-WY-Za-wy-z]";
var extension = "(?<extension>" + singleton + "(-[A-Za-z0-9]{2,8})+)";
var variant = "(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})";
var region = "(?<region>[A-Za-z]{2}|[0-9]{3})";
var script = "(?<script>[A-Za-z]{4})";
var extlang = "(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2})";
var language = "(?<language>([A-Za-z]{2,3}(-" + extlang + ")?)|[A-Za-z]{4}|[A-Za-z]{5,8})";
var langtag = "(" + language + "(-" + script + ")?" + "(-" + region + ")?" + "(-" + variant + ")*" + "(-" + extension + ")*" + "(-" + privateUse + ")?" + ")";
var languageTag = @"^(" + grandfathered + "|" + langtag + "|" + privateUse + ")$";

Console.WriteLine(languageTag);

我不能保证它的正确性(我可能犯了拼写错误),但它在附录 A 中的示例中运行良好。

根据您的环境,您可能需要删除命名的捕获组"?<...>"

Looks like this:

^((?<grandfathered>(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|
i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|
cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?<language>
([A-Za-z]{2,3}(-(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})
(-(?<script>[A-Za-z]{4}))?(-(?<region>[A-Za-z]{2}|[0-9]{3}))?(-(?<variant>[A-Za-z0-9]{5,8}
|[0-9][A-Za-z0-9]{3}))*(-(?<extension>[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*
(-(?<privateUse>x(-[A-Za-z0-9]{1,8})+))?)|(?<privateUse>x(-[A-Za-z0-9]{1,8})+))$

Here is the code to generate it (in C#):

var regular = "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)";
var irregular = "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)";
var grandfathered = "(?<grandfathered>" + irregular + "|" + regular + ")";
var privateUse = "(?<privateUse>x(-[A-Za-z0-9]{1,8})+)";
var singleton = "[0-9A-WY-Za-wy-z]";
var extension = "(?<extension>" + singleton + "(-[A-Za-z0-9]{2,8})+)";
var variant = "(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})";
var region = "(?<region>[A-Za-z]{2}|[0-9]{3})";
var script = "(?<script>[A-Za-z]{4})";
var extlang = "(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2})";
var language = "(?<language>([A-Za-z]{2,3}(-" + extlang + ")?)|[A-Za-z]{4}|[A-Za-z]{5,8})";
var langtag = "(" + language + "(-" + script + ")?" + "(-" + region + ")?" + "(-" + variant + ")*" + "(-" + extension + ")*" + "(-" + privateUse + ")?" + ")";
var languageTag = @"^(" + grandfathered + "|" + langtag + "|" + privateUse + ")$";

Console.WriteLine(languageTag);

I cannot guarantee its correctness (I may have made typos), but it works fine on the examples in Appendix A.

Depending on your environment, you might need to remove the named capturing groups "?<...>".

临风闻羌笛 2024-12-05 23:40:37

适用于 PHP 的优化版本。

/(\A(?<grandfathered>(?:en-GB-oed|i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|t(?:a[oy]|su))|sgn-(?:BE-(?:FR|NL)|CH-DE))|(?:art-lojban|cel-gaulish|no-(?:bok|nyn)|zh-(?:guoyu|hakka|min(?:-nan)?|xiang)))|(?:(?<language>(?:[A-Za-z]{2,3}(?:-(?<extlang>[A-Za-z]{3}(?:-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(?:-(?<script>[A-Za-z]{4}))?(?:-(?<region>[A-Za-z]{2}|[0-9]{3}))?(?:-(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(?:-(?<extension>[0-9A-WY-Za-wy-z](?:-[A-Za-z0-9]{2,8})+))*)(?:-(?<privateUse>x(?:-[A-Za-z0-9]{1,8})+))?\z)?/Di

An optimized version that works in PHP.

/(\A(?<grandfathered>(?:en-GB-oed|i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|t(?:a[oy]|su))|sgn-(?:BE-(?:FR|NL)|CH-DE))|(?:art-lojban|cel-gaulish|no-(?:bok|nyn)|zh-(?:guoyu|hakka|min(?:-nan)?|xiang)))|(?:(?<language>(?:[A-Za-z]{2,3}(?:-(?<extlang>[A-Za-z]{3}(?:-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(?:-(?<script>[A-Za-z]{4}))?(?:-(?<region>[A-Za-z]{2}|[0-9]{3}))?(?:-(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(?:-(?<extension>[0-9A-WY-Za-wy-z](?:-[A-Za-z0-9]{2,8})+))*)(?:-(?<privateUse>x(?:-[A-Za-z0-9]{1,8})+))?\z)?/Di
°如果伤别离去 2024-12-05 23:40:37

Javascript 会控制重复的命名捕获组,因此您必须将 ? 的第二次使用更改为 ?。编译为:

/^((?<grandfathered>(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?<language>([A-Za-z]{2,3}(-(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?<script>[A-Za-z]{4}))?(-(?<region>[A-Za-z]{2}|[0-9]{3}))?(-(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?<extension>[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?<privateUse>x(-[A-Za-z0-9]{1,8})+))?)|(?<privateUse1>x(-[A-Za-z0-9]{1,8})+))$/

这是构建它的方法:

let privateUseUsed = 0
const privateUse = () => "(?<privateUse" + (privateUseUsed++) + ">x(-[A-Za-z0-9]{1,8})+)"
const grandfathered = "(?<grandfathered>" +
      /* irregular */ (
        "en-GB-oed" +
          "|" + "i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)" +
          "|" + "sgn-(?:BE-FR|BE-NL|CH-DE)"
      ) +
      "|" + /* regular */ (
        "art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang"
      ) +
      ")"
const langtag = "(" +
      "(?<language>" + (
        "([A-Za-z]{2,3}(-" +
          "(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2})" +
          ")?)|[A-Za-z]{4,8})"
      ) +
      "(-" + "(?<script>[A-Za-z]{4})" + ")?" +
      "(-" + "(?<region>[A-Za-z]{2}|[0-9]{3})" + ")?" +
      "(-" + "(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})" + ")*" +
      "(-" + "(?<extension>" + (
        /* singleton */ "[0-9A-WY-Za-wy-z]" +
          "(-[A-Za-z0-9]{2,8})+)"
      ) +
      ")*" +
      "(-" + privateUse() + ")?" +
      ")"
const languageTagReStr = "^(" + grandfathered + "|" + langtag + "|" + privateUse() + ")$";

编辑:事实证明 ff 不支持命名捕获组,因此您必须使用 .replace(/\?/g, '') 或者开玩笑,首先将它们排除在外:

const grandfathered = "(" +
      /* irregular */ "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)" +
      "|" +
      /* regular */ "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)" +
      ")";
const langtag = "(" +
      "(" + (
        "([A-Za-z]{2,3}(-" +
          "([A-Za-z]{3}(-[A-Za-z]{3}){0,2})" +
          ")?)|[A-Za-z]{4}|[A-Za-z]{5,8})"
      ) +
      "(-" + "([A-Za-z]{4})" + ")?" +
      "(-" + "([A-Za-z]{2}|[0-9]{3})" + ")?" +
      "(-" + "([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})" + ")*" +
      "(-" + "(" + (
        /* singleton */ "[0-9A-WY-Za-wy-z]" +
          "(-[A-Za-z0-9]{2,8})+)"
      ) +
      ")*" +
      "(-" + "(x(-[A-Za-z0-9]{1,8})+)" + ")?" +
      ")";
const languageTag = RegExp("^(" + grandfathered + "|" + langtag + "|" + "(x(-[A-Za-z0-9]{1,8})+)" + ")$");

使用 languageTag.test('en-us') 进行测试

Javascript polices duplicate named capture groups so you have to change the 2nd use of ?<privateUse> to e.g. ?<privateUse1>. Compiles to:

/^((?<grandfathered>(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)|(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang))|((?<language>([A-Za-z]{2,3}(-(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2}))?)|[A-Za-z]{4}|[A-Za-z]{5,8})(-(?<script>[A-Za-z]{4}))?(-(?<region>[A-Za-z]{2}|[0-9]{3}))?(-(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3}))*(-(?<extension>[0-9A-WY-Za-wy-z](-[A-Za-z0-9]{2,8})+))*(-(?<privateUse>x(-[A-Za-z0-9]{1,8})+))?)|(?<privateUse1>x(-[A-Za-z0-9]{1,8})+))$/

Here's a way to construct it:

let privateUseUsed = 0
const privateUse = () => "(?<privateUse" + (privateUseUsed++) + ">x(-[A-Za-z0-9]{1,8})+)"
const grandfathered = "(?<grandfathered>" +
      /* irregular */ (
        "en-GB-oed" +
          "|" + "i-(?:ami|bnn|default|enochian|hak|klingon|lux|mingo|navajo|pwn|tao|tay|tsu)" +
          "|" + "sgn-(?:BE-FR|BE-NL|CH-DE)"
      ) +
      "|" + /* regular */ (
        "art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang"
      ) +
      ")"
const langtag = "(" +
      "(?<language>" + (
        "([A-Za-z]{2,3}(-" +
          "(?<extlang>[A-Za-z]{3}(-[A-Za-z]{3}){0,2})" +
          ")?)|[A-Za-z]{4,8})"
      ) +
      "(-" + "(?<script>[A-Za-z]{4})" + ")?" +
      "(-" + "(?<region>[A-Za-z]{2}|[0-9]{3})" + ")?" +
      "(-" + "(?<variant>[A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})" + ")*" +
      "(-" + "(?<extension>" + (
        /* singleton */ "[0-9A-WY-Za-wy-z]" +
          "(-[A-Za-z0-9]{2,8})+)"
      ) +
      ")*" +
      "(-" + privateUse() + ")?" +
      ")"
const languageTagReStr = "^(" + grandfathered + "|" + langtag + "|" + privateUse() + ")
quot;;

Edit: turns out ff doens't support named capture groups so you have to strip them out with .replace(/\?<a-zA-Z>/g, '') or jest leave them out in the first place:

const grandfathered = "(" +
      /* irregular */ "(en-GB-oed|i-ami|i-bnn|i-default|i-enochian|i-hak|i-klingon|i-lux|i-mingo|i-navajo|i-pwn|i-tao|i-tay|i-tsu|sgn-BE-FR|sgn-BE-NL|sgn-CH-DE)" +
      "|" +
      /* regular */ "(art-lojban|cel-gaulish|no-bok|no-nyn|zh-guoyu|zh-hakka|zh-min|zh-min-nan|zh-xiang)" +
      ")";
const langtag = "(" +
      "(" + (
        "([A-Za-z]{2,3}(-" +
          "([A-Za-z]{3}(-[A-Za-z]{3}){0,2})" +
          ")?)|[A-Za-z]{4}|[A-Za-z]{5,8})"
      ) +
      "(-" + "([A-Za-z]{4})" + ")?" +
      "(-" + "([A-Za-z]{2}|[0-9]{3})" + ")?" +
      "(-" + "([A-Za-z0-9]{5,8}|[0-9][A-Za-z0-9]{3})" + ")*" +
      "(-" + "(" + (
        /* singleton */ "[0-9A-WY-Za-wy-z]" +
          "(-[A-Za-z0-9]{2,8})+)"
      ) +
      ")*" +
      "(-" + "(x(-[A-Za-z0-9]{1,8})+)" + ")?" +
      ")";
const languageTag = RegExp("^(" + grandfathered + "|" + langtag + "|" + "(x(-[A-Za-z0-9]{1,8})+)" + ")
quot;);

Test with languageTag.test('en-us')

丢了幸福的猪 2024-12-05 23:40:37

如果使用基于 CLDR 的函数集,例如 PHP 的 intl< /a> 扩展名,您可以使用以下函数检查 intl 数据库中是否存在语言环境:

<?php
 function is_locale($locale=''){
  // STANDARDISE INPUT
  $locale=locale_canonicalize($locale);

  // LOAD ARRAY WITH LOCALES
  $locales=resourcebundle_locales(NULL);

  // RETURN WHETHER FOUND
  return (array_search($locale,$locales)!==F);
 }
?>

加载和搜索数据大约需要半毫秒,因此不会太多性能上的成功。

当然,它只会在与所使用的 PHP 版本一起提供的 CLDR 版本的数据库中查找那些内容,但会随着每个后续 PHP 版本进行更新。

If using a CLDR-based function set, like PHP's intl extension, you can check if a locale exists in the intl database using a function like:

<?php
 function is_locale($locale=''){
  // STANDARDISE INPUT
  $locale=locale_canonicalize($locale);

  // LOAD ARRAY WITH LOCALES
  $locales=resourcebundle_locales(NULL);

  // RETURN WHETHER FOUND
  return (array_search($locale,$locales)!==F);
 }
?>

It takes about half a millisecond to load and search the data, so it won't be too much of a performance hit.

Of course, it will only find those in the database of the CLDR version supplied with the PHP version used, but will be updated with each subsequent PHP release.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文