Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 如何使用正则表达式检查用户名格式_Ruby On Rails_Ruby_Regex - Fatal编程技术网

Ruby on rails 如何使用正则表达式检查用户名格式

Ruby on rails 如何使用正则表达式检查用户名格式,ruby-on-rails,ruby,regex,Ruby On Rails,Ruby,Regex,我需要使用正则表达式检查用户名格式。 我的用户名标准是: 必须包含1个或多个字母,任意位置 可以在任何地方包含任意数量的数字 可以在任何位置包含最多2个或u3 ^[0-9\-\\*[a-z | a-z]+[0-9\-\\*$是我使用的,但这将拒绝使用诸如123hi123hi或hi123hi之类的用户名。我需要一些不依赖于字符串位置的东西 我使用RubyonRails来匹配字符串 Rails的一个非常低效的Ruby函数版本是: validate :check_username def chec

我需要使用正则表达式检查用户名格式。 我的用户名标准是:

  • 必须包含1个或多个字母,任意位置

  • 可以在任何地方包含任意数量的数字
  • 可以在任何位置包含最多2个或u3
^[0-9\-\\*[a-z | a-z]+[0-9\-\\*$
是我使用的,但这将拒绝使用诸如
123hi123hi
hi123hi
之类的用户名。我需要一些不依赖于字符串位置的东西

我使用RubyonRails来匹配字符串

Rails的一个非常低效的Ruby函数版本是:

validate :check_username
def check_username
  if self.username.count("-") > 2
    errors.add(:username, "cannot contain more than 2 dashes")
  elsif self.username.count("_") > 2
    errors.add(:username, "cannot contain more than 2 underscores")
  elsif self.username.count("a-zA-Z") < 1
    errors.add(:username, "must contain a letter")
  elsif (self.username =~ /^[0-9a-zA-Z\-_]+$/) !=0
    errors.add(:username, "cannot contain special characters")
  end
end
验证:检查\u用户名
def check_用户名
如果self.username.count(“-”)大于2
错误。添加(:用户名,“不能包含超过2个破折号”)
elsif self.username.count(“”)>2
错误。添加(:用户名,“不能包含超过2个下划线”)
elsif self.username.count(“a-zA-Z”)<1
错误。添加(:用户名,“必须包含字母”)
elsif(self.username=~/^[0-9a-zA-Z\-\-\\\+$/)=0
错误。添加(:用户名,“不能包含特殊字符”)
结束
结束

这是您的正则表达式的改进版本

^[\w-]*[A-Za-z]+[\w-]*$
但这将无法计算出有多少个或uu,因此您需要另一个正则表达式来过滤或在代码中手动计算。 这是用于检查的正则表达式,不考虑其位置,仅限两个或两个以下[-\]:

^[A-Za-z\d]*[-_]{0,1}[A-Za-z\d]*[-_]{0,1}[A-Za-z\d]*$

如果只允许字母、数字、破折号和下划线

其他一切都被认为是一种特殊的性格

我认为这只是你的模式需要否定

而不是
(self.username=~/^[0-9a-zA-Z\-\-\\+$/)=0

请尝试
(self.username=~/^[^0-9a-zA-Z\-\\+$/)=0

或者
(self.username=~/^[\W-]+$/)>0


另外,为什么不对特殊字符进行计数,就像上面的条件一样?

这里有两种方法可以使用

构造单个正则表达式

def username_valid?(username)
  cnt = username.each_char.with_object(Hash.new(0)) do |c,cnt|
    case c
    when /\d/
    when /[[:alpha:]]/
      cnt[:letter] += 1
    when '-'
      cnt[:hyphen] += 1
    when '_'
      cnt[:underscore] += 1
    else
      return false
    end
  end
  cnt.fetch(:letter, 0) > 0 && cnt.fetch(:hyphen, 0) <= 2 &&
    cnt.fetch(:underscore, 0) <= 2
end

username_valid? "Bob"           #=> true 
username_valid? "Bob1_23_-"     #=> true 
username_valid? "z"             #=> true 
username_valid? "123--_"        #=> false (no letters) 
username_valid? "Melba1-23--_"  #=> false (3 hyphens)
username_valid? "Bob1_23_-$"    #=> false ($ not permitted)
由于正则表达式与字符串中字符的顺序有关,因此必须为以下每个组合构造一个正则表达式,然后将这些正则表达式“或”转换为单个正则表达式

  • 一个字母,零连字符,零下划线
  • 一个字母,零连字符,一个下划线
  • 一个字母,零连字符,两个下划线
  • 一个字母,一个连字符,零下划线
  • 一个字母,一个连字符,一个下划线
  • 一个字母,一个连字符,两个下划线
  • 一个字母,两个连字符,零下划线
  • 一个字母,两个连字符,一个下划线
  • 一个字母,两个连字符,两个下划线
数字和附加字母可以出现在用户名中的任何位置

让我们将这些正则表达式称为
t0
t1
,…,
t8
。所需的单个整体正则表达式为:

/#{t0}|#{t1}|...|#{t8}/

让我们考虑<代码> T4(一个字母,一个连字符,一个下划线)的构造。 这种组合有六种可能的订单

  • 字母、连字符、下划线
  • 字母、下划线、连字符
  • 连字符、字母、下划线
  • 连字符、下划线、字母
  • 下划线、字母、连字符
  • 下划线、连字符、字母
我们需要为这六个顺序中的每一个构造正则表达式(
r0
r1
,…,
r5
),然后“或”它们以获得
t4

t4 = /#{r0}|#{r1}|#{r2}|#{r3}|#{r4}|#{r5}/ 

现在我们考虑构造一个正则表达式>代码> R0,它将实现这些排序中的第一个(一个字母,一个连字符,一个下划线):

其他五个
ri
的构造都类似

然后,我们需要计算除第五个组合之外的八个组合中的每个组合的
ti
<代码>t0(一个字母,零连字符,零下划线)很简单:

相比之下,
t8
(一个字母、两个连字符、两个下划线)的正则表达式要比
t4
(如上所述)长得多,因为必须为
5中的每一个手工创建正则表达式/(2!*2!)#=>30个订单(
r0
r1
,…,
r29

现在很明显,使用单个正则表达式并不是验证用户名的正确工具

不要构造单个正则表达式

def username_valid?(username)
  cnt = username.each_char.with_object(Hash.new(0)) do |c,cnt|
    case c
    when /\d/
    when /[[:alpha:]]/
      cnt[:letter] += 1
    when '-'
      cnt[:hyphen] += 1
    when '_'
      cnt[:underscore] += 1
    else
      return false
    end
  end
  cnt.fetch(:letter, 0) > 0 && cnt.fetch(:hyphen, 0) <= 2 &&
    cnt.fetch(:underscore, 0) <= 2
end

username_valid? "Bob"           #=> true 
username_valid? "Bob1_23_-"     #=> true 
username_valid? "z"             #=> true 
username_valid? "123--_"        #=> false (no letters) 
username_valid? "Melba1-23--_"  #=> false (3 hyphens)
username_valid? "Bob1_23_-$"    #=> false ($ not permitted)
该方法可以改为在确定正则表达式不正确时立即写入以返回
false

def username_valid?(username)
  cnt = username.each_char.with_object(Hash.new(0)) do |c,cnt|
    case c
    when /\d/
    when /[[:alpha:]]/
      cnt[:letter] += 1
    when '-'
      return false if cnt[:hyphen] == 2 
      cnt[:hyphen] += 1
    when '_'
      return false if cnt[:underscore] == 2 
      cnt[:underscore] += 1
    else
      return false
    end
  end
  cnt.fetch(:letter, 0) > 0
end

对于正则表达式来说,这是一个不好的用法,因为您的数据结构不够。相反,一系列简单的测试将告诉您需要了解的内容:

def valid?(str)
  str[/[a-z]/i] && str.tr('^-_', '').size <= 2
end

%w(123hi123hi hi123hi).each do |username|
  username # => "123hi123hi", "hi123hi"
  valid?(username) # => true,         true
end
所以相反

def valid?(str)
  str.downcase.tr('^a-z', '').size >= 0 && str.tr('^-_', '').size <= 2
end
规则


可以在任何地方包含任意数量的数字


不值得测试,所以我忽略了它。

^
在Ruby中表示行的开头,而不是字符串;您几乎总是想使用
\A
来代替。类似地,
\z
而不是
$
。但是使用
^
$
可以允许用户名通过包含换行符的字符串,这就是为什么需要使用字符串锚(
\A
\z
)而不是行锚(
^
$
)。您是说
^\w*$
与任何单词的两行匹配吗?OP的
check_username
方法显示用户名可能包含,例如,两个连字符和一个下划线。你的正则表达式不允许这样。它也没有强制要求它必须至少包含一个字母。请注意,
[-\]{0,1}
[-\]{,1}
或更简单的是,
[-\]?
相同。我听到的是他说
计数(连字符或下划线)
^
在Ruby中表示行的开头,而不是字符串;您几乎总是想使用
\A
来代替。类似地,括号内的
\z
而不是
$
^
是对这些括号内其余表达式的否定。
def valid?(str)
  str[/[a-z]/i] && str.tr('^-_', '').size <= 2
end

%w(123hi123hi hi123hi).each do |username|
  username # => "123hi123hi", "hi123hi"
  valid?(username) # => true,         true
end
/[a-z]/i
def valid?(str)
  str.downcase.tr('^a-z', '').size >= 0 && str.tr('^-_', '').size <= 2
end
'123hi123hi'.downcase # => "123hi123hi"
            .tr('^a-z', '') # => "hihi"
            .size # => 4

'hi123hi'.downcase # => "hi123hi"
         .tr('^a-z', '') # => "hihi"
         .size # => 4

'hi-123_hi'.downcase # => "hi-123_hi"
           .tr('^a-z', '') # => "hihi"
           .size # => 4