【问题标题】:Regex - number of characters for sequence正则表达式 - 序列的字符数
【发布时间】:2019-04-11 23:43:27
【问题描述】:

我有以下模式:

<tag-2>B1</tag-2>
<tag-3>A12</tag-3>
<tag-4>M123</tag-4>
//etc

始终只有一个字母和数字。 我需要创建一个正则表达式,它使用标签中的数字并将其应用于标签之间的序列。我知道我可以使用反向引用,但我不知道如何构造正则表达式。这是不完整的正则表达式:

"^<tag-([2-9])>[A-Z][0-9]/*how to apply here number from the tag ?*/</tag-\\1>$"

编辑

以下字符串不匹配:

<tag-2>11</tag-2> //missing letter
<tag-2>BB</tag-2> // missing digit
<tag-3>B123</tag-3> //too many digits
<tag-3>AA1</tag-3> //should be only one letter and two digits
<tag-4>N12</tag-4> //too few digits

【问题讨论】:

  • 不清楚您所说的“将其应用于标签之间的序列”是什么意思 - 也许您可以举一个预期输出的例子?
  • 请参阅编辑
  • 看起来涉及一些转换,而不仅仅是匹配
  • 我问题开头的@Sarcoma 是匹配模式的字符串
  • tag-#指的是文本中的位数?请清楚您应用的规则。我们不是来解决逻辑难题的。

标签: regex


【解决方案1】:

正则表达式不能包含作为反向引用值的函数的元素(反向引用本身除外)。这是因为正则表达式从构造之时起就是静态的。

但是,可以通过两个步骤提取所需的字符串,或得出该字符串不包含有效子字符串的结论。首先尝试将字符串与/&lt;tag-(\d+)&gt; 匹配,其中捕获组的内容在转换为整数后等于以大写字母开头并后跟数字的字符串的长度。然后,该信息可用于构造第二个正则表达式,用于验证匹配的其余部分并提取所需的字符串。

我将使用 Ruby 来说明如何在这里完成。即使对不熟悉 Ruby 的读者来说,这些操作(当然还有两个正则表达式)也应该很清楚。

代码

R = /<tag-(\d+)>/           # a constant

def doit(str)
  m = str.match(R)          # obtain a MatchData object; else nil
  return nil if m.nil?      # finished if no match
  n = m[1].to_i-1           # required number of digits
  r = /\A\p{Lu}\d{#{n}}(?=<\/tag-#{m[1]}>)/
                            # regular expression for second match
  str[m.end(0).to_i..-1][r] # extract the desired string; else nil
end

示例

arr = <<_.each_line.map(&:chomp)
<tag-2>B1</tag-2>
<tag-3>A12</tag-3>
<tag-4>M123</tag-4>
<tag-2>11</tag-2>
<tag-2>BB</tag-2>
<tag-3>B123</tag-3>
<tag-3>AA1</tag-3>
<tag-4>N12</tag-4>
_
  #=> ["<tag-2>B1</tag-2>",   "<tag-3>A12</tag-3>",
  #    "<tag-4>M123</tag-4>", "<tag-2>11</tag-2>",
  #    "<tag-2>BB</tag-2>",   "<tag-3>B123</tag-3>",
  #    "<tag-3>AA1</tag-3>",  "<tag-4>N12</tag-4>"] 

arr.map do |line|
  s = doit(line)
  s = 'nil' if s.nil?
  puts "#{line.ljust(22)}: #{s}"
end
<tag-2>B1</tag-2>     : B1
<tag-3>A12</tag-3>    : A12
<tag-4>M123</tag-4>   : M123
<tag-2>11</tag-2>     : nil
<tag-2>BB</tag-2>     : nil
<tag-3>B123</tag-3>   : nil
<tag-3>AA1</tag-3>    : nil
<tag-4>N12</tag-4>    : nil    

说明

注意(?=&lt;\/tag-#{m[1]}&gt;)(方法体中r的一部分)是一个正向前瞻,这意味着"&lt;\/tag-#{m[1]}&gt;"(用#{m[1]}替换)必须匹配,但不是返回的匹配的一部分。

分步计算如下。

str = "<tag-2>B1</tag-2>"

m = str.match(R)
  #=> #<MatchData "<tag-2>" 1:"2"> 
m[0]
  #=> "<tag-2>"  (match)
m[1]
  #=> "2"  (contents of capture group 1)
m.end(0)
  #=> 7  (index of str where the match ends, plus 1) 
m.nil?
  #=> false  (do not return)
n = m[1].to_i-1
  #=> 1  (number of digits required)
r = /\A\p{Lu}\d{#{n}}(?=\<\/tag\-#{m[1]}\>)/
  #=> /\A\p{Lu}\d{1}(?=\<\/tag\-2\>)/
s = str[m.end(0).to_i..-1]
  #=> str[7..-1]
  #=> "B1</tag-2>" 
s[r]
  #=> "B1" 

【讨论】:

    【解决方案2】:

    看起来您正在尝试创建一个模式来解释数字以确定字符串的长度。我不知道在任何正则表达式引擎中有任何功能可以自动执行此过程,但可以通过枚举您希望处理的所有情况以更手动的方式完成。

    例如,标签 2 到 9 可以这样处理:

    • &lt;tag-2&gt;: ^&lt;tag-2&gt;[A-Z][0-9]&lt;/tag-2&gt;$
    • &lt;tag-3&gt;: ^&lt;tag-3&gt;[A-Z][0-9]{2}&lt;/tag-3&gt;$
    • &lt;tag-4&gt;: ^&lt;tag-4&gt;[A-Z][0-9]{3}&lt;/tag-4&gt;$
    • &lt;tag-5&gt;: ^&lt;tag-5&gt;[A-Z][0-9]{4}&lt;/tag-5&gt;$
    • &lt;tag-6&gt;: ^&lt;tag-6&gt;[A-Z][0-9]{5}&lt;/tag-6&gt;$
    • &lt;tag-7&gt;: ^&lt;tag-7&gt;[A-Z][0-9]{6}&lt;/tag-7&gt;$
    • &lt;tag-8&gt;: ^&lt;tag-8&gt;[A-Z][0-9]{7}&lt;/tag-8&gt;$
    • &lt;tag-9&gt;: ^&lt;tag-9&gt;[A-Z][0-9]{8}&lt;/tag-9&gt;$

    通过删除分组和反向引用,您消除了在尝试组合正则表达式模式时可能出现的一些复杂情况,并且可以产生以下结果:

    ^(&lt;tag-2&gt;[A-Z][0-9]&lt;/tag-2&gt;|&lt;tag-3&gt;[A-Z][0-9]{2}&lt;/tag-3&gt;|&lt;tag-4&gt;[A-Z][0-9]{3}&lt;/tag-4&gt;|&lt;tag-5&gt;[A-Z][0-9]{4}&lt;/tag-5&gt;|&lt;tag-6&gt;[A-Z][0-9]{5}&lt;/tag-6&gt;|&lt;tag-7&gt;[A-Z][0-9]{6}&lt;/tag-7&gt;|&lt;tag-8&gt;[A-Z][0-9]{7}&lt;/tag-8&gt;|&lt;tag-9&gt;[A-Z][0-9]{8}&lt;/tag-9&gt;)$

    【讨论】:

    • 它有效,我知道这样的解决方案,但我想知道是否可以构造一个正则表达式。
    • 从反向引用构造一个量词值需要重建用于处理字符串的状态机。典型的正则表达式引擎不支持这一点。有关详细信息,请参阅此问题:stackoverflow.com/questions/681474/…
    猜你喜欢
    • 2018-01-09
    • 1970-01-01
    • 2021-12-29
    • 1970-01-01
    • 2015-07-19
    • 2015-10-10
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    相关资源
    最近更新 更多