按照特定规则分隔字符和数字

时间:2016-10-06 12:08:20

标签: ruby regex

我正在尝试区分航班号。

Example: 
flightno = "FR556"
split_data = flightno.upcase.match(/([A-Za-z]+)(\d+)/)
first  = split_data[1] # FR
second = split_data[1] # 556

然后我继续查询数据库以在此示例中找到基于FR的航空公司,并应用一些结果为Ryanair的逻辑。

我的问题是航班号可能是:

flightno = "U21920"
split_data = flightno.upcase.match(/([A-Za-z]+)(\d+)/)
first  = split_data[1] # U
second = split_data[1] # 21920

我基本上希望首先成为U2而不仅仅是U.这是用于通过IATA代码搜索航空公司的数据库,在这种情况下是U2

****编辑** 为了清楚起见,我在提问时提出了一些术语错误。由于预订参考号码的复杂性,输入来自乘客提供的任何内容。例如,对于easyJet航班,乘客可以只输入航空公司提供的EZY1920或U21920,以便乘客真正无知。

" EZY" =国际民航组织 " U2" = IATA

我接受用户的意见并尝试将ICAO或IATA与航班号分开,#34; 1920"但是从用户体验的角度来看,没有办法确定没有搜索数据库或分离我觉得麻烦的输入。

使用正则表达式将字符与数字分开,直到用户输入IATA作为其航班号的一部分(乘客不知道其中的差异),正如您在上面的示例中所看到的,这会混淆正则表达式。 **

麻烦的是我无法想到任何其他带有航班号的模式。它们总是至少有两个由字母或字母和数字混合组成的字符,长度可以是3个字符。数字部分可以短至1,但也可以长达4 - 总是数字。

**** **编辑 正如评论中提到的那样,没有固定的大小,但有一件事总是正确的(至少到目前为止)是第一个字符始终是一个字母,无论它是ICAO还是IATA。 在考虑到目前为止输入的每个机构之后,我想知道是否搜索数据库并返回航空公司的IATA或ICAO与用户提供的前两个字母匹配(U2),(FR),(EZ)可能是一种方式然而,如果国际民航组织或国际航空运输协会与另一家航空公司相匹配,则会出现明显的问题,例如" EZY" &安培; " EZT&#34 ;.这不是未来的证据,我正在寻找更好的红宝石或正则表达式解决方案。**

感谢您的意见。

修改

我已在下面回答了我自己的问题。虽然其他答案提供了处理某些条件的解决方案,但如果航班号以数字开头,那么它就会掉下来,所以我制定了一个粗鲁但是迄今为止可以稳定地分析字符串的数字,然后计算出它是ICAO还是IATA从那起。

2 个答案:

答案 0 :(得分:1)

我想到的一个解决方案是,您将给定的航班号与完整的ICAO / IATA代码列表相匹配:https://raw.githubusercontent.com/datasets/airport-codes/master/data/airport-codes.csv

花点时间与谷歌可能会给你一个更合适的列表。

然后使用您的航班号的前三个字符(如果这是最大值)来查找icao代码中的匹配项。如果找到一个,你就会知道在哪里分开你的字符串。

这是一个应该让你在轨道上的最小丑陋的例子。随意更新!

ICAOCODES = %w(FR DEU U21) # grab your data here

def retrieve_flight_information(flightnumber)
  ICAOCODES.each do |icao|
    co = flightnumber.match(icao).to_s
    if co.length > 0
      # airline
      puts co
      # flight number
      puts flightnumber.gsub(co,'')
    end
  end
end

retrieve_flight_information("FR556")
#=> FR
#=> 556
retrieve_flight_information("U21214123")
#=> U21
#=> 214123

最大的缺陷在于使用.gsub()因为它可能会弄乱您的航班号,以防它看起来像这样:"FR21413FR2" 但是你会发现很多解决这个问题的方法。

正如评论中所提到的,icao代码列表并不是您想要的。但这里的相关内容是,您需要一个可以安全地比较的字符串列表。

答案 1 :(得分:0)

我有一个相当粗鲁的解决方案似乎在我迄今为止可以抛出的所有场景中都有效。我想让其他可能觉得有用的人可以使用它吗?

航班代码/数字的一般经验法则似乎是:

IATA:两个由任意组合字母和数字组成的字符 国际民航组织:仅由字母组成的三个字符(迄今为止)

考虑到这一点,如果我们需要根据前三个字符的条件由IATA或ICAO搜索数据库,我们应该能够解决。

首先我们获取航班号并转换为大写

string  = "U21920".upcase

接下来,我们会分析前三个字符以检查是否有任何数字。

first_three = string[0,3] # => U21

first_three中是否有数字?

if first_three =~ /\d/ # => true
iata = first_three[0,2] # => If true lets get rid of the last character
# Now we go to the database searching IATA (U2)

search = Airline.where('iata LIKE ?', "#{iata}%") # => Starts with search, just in case

否则,如果字符串中找不到数字

else
 icao = string.match(/([A-Za-z]+)(\d+)/)
 search = Airline.where('icao LIKE ?', "#{icao[1]}%")

这似乎适用于今天从一些主要的机场实时出发/到达委员会测试的随机航班号。这是一个有趣的问题,因为一些航空公司发行国际民航组织或国际航空运输协会代码作为航班号码的一部分,这意味着乘客不会知道任何不同,更不用说,一些机场以他们自己的格式提供航班信息,所以在那里不是对国际民航组织和国际航空运输协会建设的改变,那么上述工作应该有效。

以下是您可以运行的示例脚本

<强> test.rb

puts "What is your flight number?"
string  = gets.upcase
first_three = string[0,3]
puts "Taking first three from #{string} is #{first_three}"

if first_three =~ /\d/         # Calling String's =~ method.
 puts "The String #{first_three} DOES have a number in it."
 iata = first_three[0,2]
 search = Airline.where('iata LIKE ?', "#{iata}%")
 puts "Searching Airlines starting with IATA #{iata} = #{search.count}"
 puts "Found #{search.first.name} from IATA #{iata}"
else
 puts "The String #{first_three} does not have a number in it."
 icao = string.match(/([A-Za-z]+)(\d+)/)
 search = Airline.where('icao LIKE ?', "#{icao[1]}%")
 puts "Searching Airlines starting with ICAO #{icao[1]} = #{search.count}"
 puts "Found #{search.first.name} from IATA #{icao[1]}"
end

<强>航空公司

Airline(id: integer, name: string, iata: string, icao: string, created_at: datetime, updated_at: datetime )

将其粘贴在您的lib文件夹中并运行

  

rails runner lib / test.rb

显然,您可以删除所有的puts语句以直接获得结果。我在运行脚本时使用rails runner来访问我的Airline模型。