正则表达式 - 如果开始匹配则匹配结束
Regular Expression - Match End if Start is Match
我要匹配以下字符串:
[anything can be here]
[{anything can be here}]
我可以只使用一个正则表达式来实现吗?
我目前正在使用这个 '^\[({)?.+(})?]$'
,但它也会匹配:
[anything can be here}]
[{anything can be here]
只有在使用 {
时,我才需要匹配 }
。
请注意,我只能使用正则表达式匹配函数,因为我已将其实现为 SQL CLR
函数,以便在 T-SQL
语句中使用它。
您的正则表达式 ^\[({)?.+(})?]$
将仅匹配单个字符串,例如 [{...}]
或 [{...]
,因为 1) 您有锚点 (^$
),并且两个大括号都存在同样的模式。
我建议使用负向后视来避免匹配 []
-ed 字符串中只有 1 个大括号的字符串,如下所示:
var rgx = new Regex(@"((?!\[\{[^}]+\]|\[[^{]+\})\[\{?.+?\}?\])");
var tst = "[anything can be here] [{anything can be here}] [anything can be here}] [{anything can be here]";
var mtch = rgx.Matches(tst).Cast<Match>().ToList();
这将确保您匹配 []
-ed 字符串,即使在更大的上下文中也是如此。
结果:
我成功了:\[[^{].*[^}]\]|\[\{.*\}\]
编辑
正如 OP 指出的那样,括号之间需要一些东西,所以 'one or more' 匹配更合适:
\[[^{].+[^}]\]|\[\{.+\}\]
基本上你可以这样写(逐字串):
^\[(?:{.+}|[^]{}]+)]$
你可以使用更复杂的条件语句 (?(condition)then|else)
:
^\[({)?[^]{}]+(?(1)}|)]$
(如果捕获组 1 存在,则 }
否则无)
但这种方式效率可能较低
试试这个:
\[[^{].*[^}]\]|\[[^{}]\]|\[\{.+\}\]
分解后匹配 3 种类型的字符串:
[]
周围 ≥ 2 个字符,前提是第一个字符不是 {
并且最后一个字符不是 }
[{}]
周围任何东西
[]
围绕单个非花括号字符(以前的答案未涵盖的边缘情况)
好的,我知道这个问题已经得到解答,但我想我会展示一个纯 T-SQL 解决方案作为替代方案。
DECLARE @yourTable TABLE (val VARCHAR(100));
INSERT INTO @yourTable
VALUES ('[anything can be here]'),
('[{anything can be here}]'),
('[anything can be here}]'),
('[{anything can be here]');
WITH CTE_Brackets
AS
(
SELECT val,
CASE
WHEN CHARINDEX('{',val) > 0 THEN CHARINDEX('{',val)
END AS L_curly,
CASE
WHEN CHARINDEX('}',val) > 0 THEN CHARINDEX('}',val)
END AS R_curly,
CASE
WHEN CHARINDEX('[',val) > 0 THEN CHARINDEX('[',val)
END AS L_bracket,
CASE
WHEN CHARINDEX(']',val) > 0 THEN CHARINDEX(']',val)
END AS R_bracket
FROM @yourTable
),
CTE_string
AS
(
SELECT val,
L_curly,
R_curly,
L_bracket,
R_bracket,
SUBSTRING(val,start_pos,end_pos - start_pos) val_string
FROM CTE_Brackets A
CROSS APPLY (SELECT COALESCE(L_curly,L_bracket) + 1 AS start_pos,
COALESCE(R_curly,R_bracket) AS end_pos
) CA
)
SELECT A.val,B.val
FROM CTE_string A
INNER JOIN CTE_string B
ON A.val_string = B.val_string
AND
(
(
A.L_curly IS NOT NULL
AND A.R_curly IS NULL
AND B.L_curly IS NULL
AND B.R_curly IS NOT NULL
) --left curly matching right only curly
OR
(
A.L_curly + A.R_curly IS NOT NULL
AND B.R_curly IS NULL
AND B.L_curly IS NULL
) --matches both curly to no curly
)
ORDER BY B.val
我要匹配以下字符串:
[anything can be here]
[{anything can be here}]
我可以只使用一个正则表达式来实现吗?
我目前正在使用这个 '^\[({)?.+(})?]$'
,但它也会匹配:
[anything can be here}]
[{anything can be here]
只有在使用 {
时,我才需要匹配 }
。
请注意,我只能使用正则表达式匹配函数,因为我已将其实现为 SQL CLR
函数,以便在 T-SQL
语句中使用它。
您的正则表达式 ^\[({)?.+(})?]$
将仅匹配单个字符串,例如 [{...}]
或 [{...]
,因为 1) 您有锚点 (^$
),并且两个大括号都存在同样的模式。
我建议使用负向后视来避免匹配 []
-ed 字符串中只有 1 个大括号的字符串,如下所示:
var rgx = new Regex(@"((?!\[\{[^}]+\]|\[[^{]+\})\[\{?.+?\}?\])");
var tst = "[anything can be here] [{anything can be here}] [anything can be here}] [{anything can be here]";
var mtch = rgx.Matches(tst).Cast<Match>().ToList();
这将确保您匹配 []
-ed 字符串,即使在更大的上下文中也是如此。
结果:
我成功了:\[[^{].*[^}]\]|\[\{.*\}\]
编辑 正如 OP 指出的那样,括号之间需要一些东西,所以 'one or more' 匹配更合适:
\[[^{].+[^}]\]|\[\{.+\}\]
基本上你可以这样写(逐字串):
^\[(?:{.+}|[^]{}]+)]$
你可以使用更复杂的条件语句 (?(condition)then|else)
:
^\[({)?[^]{}]+(?(1)}|)]$
(如果捕获组 1 存在,则 }
否则无)
但这种方式效率可能较低
试试这个:
\[[^{].*[^}]\]|\[[^{}]\]|\[\{.+\}\]
分解后匹配 3 种类型的字符串:
[]
周围 ≥ 2 个字符,前提是第一个字符不是{
并且最后一个字符不是}
[{}]
周围任何东西[]
围绕单个非花括号字符(以前的答案未涵盖的边缘情况)
好的,我知道这个问题已经得到解答,但我想我会展示一个纯 T-SQL 解决方案作为替代方案。
DECLARE @yourTable TABLE (val VARCHAR(100));
INSERT INTO @yourTable
VALUES ('[anything can be here]'),
('[{anything can be here}]'),
('[anything can be here}]'),
('[{anything can be here]');
WITH CTE_Brackets
AS
(
SELECT val,
CASE
WHEN CHARINDEX('{',val) > 0 THEN CHARINDEX('{',val)
END AS L_curly,
CASE
WHEN CHARINDEX('}',val) > 0 THEN CHARINDEX('}',val)
END AS R_curly,
CASE
WHEN CHARINDEX('[',val) > 0 THEN CHARINDEX('[',val)
END AS L_bracket,
CASE
WHEN CHARINDEX(']',val) > 0 THEN CHARINDEX(']',val)
END AS R_bracket
FROM @yourTable
),
CTE_string
AS
(
SELECT val,
L_curly,
R_curly,
L_bracket,
R_bracket,
SUBSTRING(val,start_pos,end_pos - start_pos) val_string
FROM CTE_Brackets A
CROSS APPLY (SELECT COALESCE(L_curly,L_bracket) + 1 AS start_pos,
COALESCE(R_curly,R_bracket) AS end_pos
) CA
)
SELECT A.val,B.val
FROM CTE_string A
INNER JOIN CTE_string B
ON A.val_string = B.val_string
AND
(
(
A.L_curly IS NOT NULL
AND A.R_curly IS NULL
AND B.L_curly IS NULL
AND B.R_curly IS NOT NULL
) --left curly matching right only curly
OR
(
A.L_curly + A.R_curly IS NOT NULL
AND B.R_curly IS NULL
AND B.L_curly IS NULL
) --matches both curly to no curly
)
ORDER BY B.val