[英]Split a database query string using regex in ruby
我有一个要分离的查询字符串
created_at BETWEEN '2018-01-01T00:00:00+05:30' AND '2019-01-01T00:00:00+05:30' AND updated_at BETWEEN '2018-05-01T00:00:00+05:30' AND '2019-05-01T00:00:00+05:30' AND user_id = 5 AND status = 'closed'
像这样
created_at BETWEEN '2018-01-01T00:00:00+05:30' AND '2019-01-01T00:00:00+05:30'
updated_at BETWEEN '2018-05-01T00:00:00+05:30' AND '2019-05-01T00:00:00+05:30'
user_id = 5
status = 'closed'
这只是一个示例字符串,我想动态分离查询字符串。 我知道不能只用AND
分割AND
因为BETWEEN .. AND
您也许可以使用regex做到这一点,但是这里有一个解析器可能适用于您的用例。 当然可以改进它,但是应该可以。
require 'time'
def parse(sql)
arr = []
split = sql.split(' ')
date_counter = 0
split.each_with_index do |s, i|
date_counter = 2 if s == 'BETWEEN'
time = Time.parse(s.strip) rescue nil
date_counter -= 1 if time
arr << i+1 if date_counter == 1
end
arr.select(&:even?).each do |index|
split.insert(index + 2, 'SPLIT_ME')
end
split = split.join(' ').split('SPLIT_ME').map{|l| l.strip.gsub(/(AND)$/, '')}
split.map do |line|
line[/^AND/] ? line.split('AND') : line
end.flatten.select{|l| !l.empty?}.map(&:strip)
end
这不是真正的正则表达式,而是一个简单的解析器。
and
或between
接空格字符。 结果从where_cause
删除,并保存在statement
。 between
是空格。 它添加到statement
然后从where_cause
删除,之后where_cause
上1 and
。 如果达到或另一个字符串的结尾匹配停止and
遇到。 and
后跟一个空格。 如果是这种情况,请从where_cause
删除它。 statement
的statements
数组,如果它不是一个空字符串。 所有匹配均不区分大小写。
where_cause = "created_at BETWEEN '2018-01-01T00:00:00+05:30' AND '2019-01-01T00:00:00+05:30' AND updated_at BETWEEN '2018-05-01T00:00:00+05:30' AND '2019-05-01T00:00:00+05:30' AND user_id = 5 AND status = 'closed'"
statements = []
until where_cause.empty?
statement = where_cause.slice!(/\A.*?(?=[\s](and|between)[\s]|\z)/mi)
if where_cause.match? /\A[\s]between[\s]/i
between = /\A[\s]between[\s].*?[\s]and[\s].*?(?=[\s]and[\s]|\z)/mi
statement << where_cause.slice!(between)
elsif where_cause.match? /\A[\s]and[\s]/i
where_cause.slice!(/\A[\s]and[\s]/i)
end
statements << statement unless statement.empty?
end
pp statements
# ["created_at BETWEEN '2018-01-01T00:00:00+05:30' AND '2019-01-01T00:00:00+05:30'",
# "updated_at BETWEEN '2018-05-01T00:00:00+05:30' AND '2019-05-01T00:00:00+05:30'",
# "user_id = 5",
# "status = 'closed'"]
注意: Ruby使用\\A
来匹配字符串的开头,并使用\\z
来匹配字符串的结尾,而不是通常的^
和$
,它们分别匹配行的开头和结尾。 请参阅regexp锚文档 。
如果愿意,可以将每个[\\s]
替换为\\s
。 我添加了它们以使正则表达式更具可读性。
请记住,该解决方案并不完美,但可能会给您一个解决问题的思路。 我之所以说这是因为它不占字and
/ between
的列名或字符串上下文。
以下是原因所在:
where_cause = "name = 'Tarzan AND Jane'"
将输出:
#=> ["name = 'Tarzan", "Jane'"]
该解决方案还假定结构正确的SQL查询。 以下查询不会导致您的想法:
where_cause = "created_at = BETWEEN AND"
# TypeError: no implicit conversion of nil into String
# ^ does match /\A[\s]between[\s]/i, but not the #slice! argument
where_cause = "id = BETWEEN 1 AND 2 BETWEEN 1 AND 3"
#=> ["id = BETWEEN 1 AND 2 BETWEEN 1", "3"]
我不确定我是否理解这个问题,尤其是考虑到先前的答案,但是如果您只是想从字符串中提取指示的子字符串,并且所有列名都以小写字母开头,则可以编写以下内容(其中str
持有问题中给出的字符串):
str.split(/ +AND +(?=[a-z])/)
#=> ["created_at BETWEEN '2018-01-01T00:00:00+05:30' AND '2019-01-01T00:00:00+05:30'",
# "updated_at BETWEEN '2018-05-01T00:00:00+05:30' AND '2019-05-01T00:00:00+05:30'",
# "user_id = 5",
# "status = 'closed'"]
正则表达式为:“匹配一个或多个空格,后跟'AND'
,后跟一个或多个空格,后跟一个包含小写字母的正向前行”。 前瞻性为正,小写字母不属于所返回匹配项的一部分。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.