Postgres 中的非贪婪捕获组
Non-greedy capture groups in Postgres
我正在尝试实现一个正则表达式来解析字符串的不同组。我收到的字符串表示客户想要将我们平台上的主要语言从 X 更改为 Y,因此它看起来像
language_change__from_english_to_spanish
language_change__from_spanish_to_somali
language_change__from_simplified_chinese_to_english
我有一个正则表达式来解析语言(原始语言,然后是新语言):
SUBSTRING(language_field FROM '^language_change__([a-zA-Z_]+)_to_[a-zA-Z_]+$')
原始语言的效果很好,但在新语言中效果不佳,因为有时有人输入 language_change__from_english_to_spanish_
。所以实际解析的是spanish_
而不是spanish
.
我知道我可以很容易地用 REPLACE
包裹我的 SUBSTRING(...)
来替换最后的 _
,但我正在尝试找到一种使用正则表达式的方法提高我的正则表达式技能。我基本上想忽略最后的 _
。但是,我无法从我的捕获组中删除 _
,因为在我们的系统中编码的某些语言有 _
:例如 simplified_chinese
。
基本上,我希望我的捕获组包括第一个 _
后跟文本(如 simplified_chinese
),但不包括 _
如果它在末尾字符串 (english_
).
所以当输入language_change__from_spanish_to_english_
时,我应该仍然捕获english
,而不是english_
作为语言。
我尝试了各种方法:
- 使用负前瞻:
SUBSTRING(language_field FROM '^language_change__[a-zA-Z_]+_to_([a-zA-Z_]+)(?!_)$')
- 使用非贪婪捕获组:
SUBSTRING(language_field FROM '^language_change__[a-zA-Z_]+_to_([a-zA-Z_]+?)$')
- 使用负先行和非贪婪捕获组的组合:
SUBSTRING(language_field FROM '^language_change__[a-zA-Z_]+_to_([a-zA-Z_]+?)(?!_)$')
我觉得我在 Whosebug 上的时间已经足够长了,所以我不会说 "nothing works",但是我在上面尝试的所有三件事仍然会产生 english_
而不是 english
我们这边进入了language_change__from_spanish_to_english_
。
有人可以指点我所缺少的吗?
您可以使用
SUBSTRING(language_field FROM '^language_change__[a-zA-Z_]+_to_([a-zA-Z_]+?)_*$')
([a-zA-Z_]+?)_*$
部分表示:
([a-zA-Z_]+?)
- 第 1 组:匹配 1 个或多个 ASCII 字母或 _
尽可能少的次数
_*
- 匹配 0 个或更多 _
个字符
$
- 在字符串末尾。
([a-zA-Z_]+?)
模式将匹配 1 个字符,然后将尝试 _*$
模式部分。如果 _*$
匹配失败,引擎将回溯并且 ([a-zA-Z_]+?)
模式将获取另一个字符并重复测试。因此,如果 _
存在于字符串的末尾,它们将不会被包含在捕获组中,它们将与 _*
部分匹配,从而从结果中被丢弃。
请参阅 this regex debugger step by step 以查看正在运行的正则表达式。
我正在尝试实现一个正则表达式来解析字符串的不同组。我收到的字符串表示客户想要将我们平台上的主要语言从 X 更改为 Y,因此它看起来像
language_change__from_english_to_spanish
language_change__from_spanish_to_somali
language_change__from_simplified_chinese_to_english
我有一个正则表达式来解析语言(原始语言,然后是新语言):
SUBSTRING(language_field FROM '^language_change__([a-zA-Z_]+)_to_[a-zA-Z_]+$')
原始语言的效果很好,但在新语言中效果不佳,因为有时有人输入 language_change__from_english_to_spanish_
。所以实际解析的是spanish_
而不是spanish
.
我知道我可以很容易地用 REPLACE
包裹我的 SUBSTRING(...)
来替换最后的 _
,但我正在尝试找到一种使用正则表达式的方法提高我的正则表达式技能。我基本上想忽略最后的 _
。但是,我无法从我的捕获组中删除 _
,因为在我们的系统中编码的某些语言有 _
:例如 simplified_chinese
。
基本上,我希望我的捕获组包括第一个 _
后跟文本(如 simplified_chinese
),但不包括 _
如果它在末尾字符串 (english_
).
所以当输入language_change__from_spanish_to_english_
时,我应该仍然捕获english
,而不是english_
作为语言。
我尝试了各种方法:
- 使用负前瞻:
SUBSTRING(language_field FROM '^language_change__[a-zA-Z_]+_to_([a-zA-Z_]+)(?!_)$')
- 使用非贪婪捕获组:
SUBSTRING(language_field FROM '^language_change__[a-zA-Z_]+_to_([a-zA-Z_]+?)$')
- 使用负先行和非贪婪捕获组的组合:
SUBSTRING(language_field FROM '^language_change__[a-zA-Z_]+_to_([a-zA-Z_]+?)(?!_)$')
我觉得我在 Whosebug 上的时间已经足够长了,所以我不会说 "nothing works",但是我在上面尝试的所有三件事仍然会产生 english_
而不是 english
我们这边进入了language_change__from_spanish_to_english_
。
有人可以指点我所缺少的吗?
您可以使用
SUBSTRING(language_field FROM '^language_change__[a-zA-Z_]+_to_([a-zA-Z_]+?)_*$')
([a-zA-Z_]+?)_*$
部分表示:
([a-zA-Z_]+?)
- 第 1 组:匹配 1 个或多个 ASCII 字母或_
尽可能少的次数_*
- 匹配 0 个或更多_
个字符$
- 在字符串末尾。
([a-zA-Z_]+?)
模式将匹配 1 个字符,然后将尝试 _*$
模式部分。如果 _*$
匹配失败,引擎将回溯并且 ([a-zA-Z_]+?)
模式将获取另一个字符并重复测试。因此,如果 _
存在于字符串的末尾,它们将不会被包含在捕获组中,它们将与 _*
部分匹配,从而从结果中被丢弃。
请参阅 this regex debugger step by step 以查看正在运行的正则表达式。