正则表达式:匹配包含数字和字母的字符串,但不包含只是数字的字符串

时间:2009-08-06 18:44:45

标签: ruby-on-rails ruby regex puzzle

问题

我希望能够使用单个正则表达式(如果可能)要求字符串适合[A-Za-z0-9_]但不允许:

  • 仅包含数字或/和符号的字符串。
  • 以符号开头或结尾的字符串
  • 彼此相邻的多个符号

有效

  • test_0123
  • t0e1s2t3
  • 0123_test
  • te0_s1t23
  • t_t

无效

  • t__t
  • ____
  • 01230123
  • _0123
  • _test
  • _test123
  • test_
  • test123_

规则的原因

这样做的目的是过滤我正在处理的网站的用户名。我出于特定的原因达成了规则。

  • 仅包含数字和/或符号的用户名可能会导致路由和数据库查找出现问题。 /users/#{id}的路由允许id成为用户的ID或用户的名称。因此,名称和ID不应该发生冲突。

  • _test看起来很奇怪,我不相信它是有效的子域名,_test.example.com

  • 我不喜欢t__t作为子域的外观。即t__t.example.com

9 个答案:

答案 0 :(得分:8)

这完全符合您的要求:

/\A(?!_)(?:[a-z0-9]_?)*[a-z](?:_?[a-z0-9])*(?<!_)\z/i
  1. 至少一个字母字符(中间的[a-z])。
  2. 不以下划线开头或结尾(开头和结尾都为(?!_)(?<!_)。)
  3. 字母字符前后可以包含任意数量的数字,字母或下划线,但每个下划线必须至少用一个数字或字母分隔(其余部分)。
  4. 编辑:事实上,由于正则表达式的其余部分是如何工作的,你甚至可能根本不需要前瞻/后瞻 - 第一个?:括号将在字母数字之前不允许下划线,并且第二个?:括号不允许使用下划线,除非它在字母数字之前:

    /\A(?:[a-z0-9]_?)*[a-z](?:_?[a-z0-9])*\z/i
    

    应该可以正常工作。

答案 1 :(得分:2)

我确定你可以把所有这些都放到一个正则表达式中,但这并不简单,我不确定为什么坚持它一个正则表达式。为什么不在验证期间使用多次传递?如果在用户创建新帐户时完成验证检查,则没有任何理由尝试将其填充到一个正则表达式中。 (也就是说,你只会一次处理一个项目,而不是数百或数千或更多。对于正常大小的用户名,几次传递应该花很少的时间,我想。)

如果名称不包含至少一个数字,则首先拒绝;如果名称不包含至少一个字母,则拒绝;然后检查开始和结束是否正确;这些传递中的每一个都可以是一个易于阅读和易于维护的正则表达式。

答案 2 :(得分:2)

怎么样:

/^(?=[^_])([A-Za-z0-9]+_?)*[A-Za-z](_?[A-Za-z0-9]+)*$/

它不使用反向引用。

修改

成功完成所有测试用例。是否与ruby兼容。

答案 3 :(得分:1)

这不会阻止“__”,但它确实得到了其余部分:

([A-Za-z]|[0-9][0-9_]*)([A-Za-z0-9]|_[A-Za-z0-9])*

这是获得所有规则的更长形式:

([A-Za-z]|([0-9]+(_[0-9]+)*([A-Za-z|_[A-Za-z])))([A-Za-z0-9]|_[A-Za-z0-9])*
那个,那很难看。我同意Telemachus,你可能不应该用一个正则表达式来做这件事,即使它在技术上是可行的。正则表达式通常是维护的痛苦。

答案 4 :(得分:1)

问题要求单个正则表达式,并暗示它应该是匹配的正则表达式,这很好,并且由其他人回答。但是,为了感兴趣,我注意到这些规则更容易直接表示为匹配的正则表达式。即:

x !~ /[^A-Za-z0-9_]|^_|_$|__|^\d+$/
  • 除了字母,数字和_
  • 之外没有其他字符
  • 无法以_
  • 开头
  • 不能以_
  • 结尾
  • 不能连续两个_s
  • 不能是所有数字

你不能在Rails validates_format_of中以这种方式使用它,但你可以将它放在类的验证方法中,我认为你仍然有更好的机会仍然能够理解你的意思,从现在起一个月或一年。

答案 5 :(得分:0)

(?=.*[a-zA-Z].*)^[A-Za-z0-9](_?[A-Za-z0-9]+)*$

这个有效。

向前看以确保字符串中至少有一个字母,然后开始消耗输入。每次有下划线时,下一个下划线前必须有一个数字或一个字母。

答案 6 :(得分:0)

你走了:

^(([a-zA-Z]([^a-zA-Z0-9]?[a-zA-Z0-9])*)|([0-9]([^a-zA-Z0-9]?[a-zA-Z0-9])*[a-zA-Z]+([^a-zA-Z0-9]?[a-zA-Z0-9])*))$

如果您想限制您想接受的符号,只需将所有[^ a-zA-Z0-9]改为包含所有允许符号的[]

答案 7 :(得分:0)

/^(?![\d_]+$)[A-Za-z0-9]+(?:_[A-Za-z0-9]+)*$/

您的问题与this one基本相同,并且要求至少有一个字符必须是字母。负向前瞻 - (?![\d_]+$) - 负责处理那部分,并且比其他人试图将其纳入基本正则表达式更容易(包括读取和写入)。

答案 8 :(得分:-2)

[A-Za-z][A-Za-z0-9_]*[A-Za-z]

这适用于你的前两条规则(因为它要求第二条规则的开头和结尾都有一个字母,它自动需要字母)。

我不确定第三条规则是否可以使用正则表达式。