如何从文本列中提取数据

时间:2016-02-05 17:21:34

标签: ruby regex

我在多行字符串中并排有两个地址:

 Adresse de prise en charge :                          Adresse d'arrivée :


  rue des capucines                                      rue des tilleuls


  92210       Saint Cloud                                67000            Strasbourg

  Tél.:                                                  Tél.:

我需要使用regexp在左侧和右侧提取地址,并将它们分配给变量。我需要匹配:

  • address1"rue des capucines 92210 Saint Cloud"
  • address2"rue des tilleuls 67000 Strasbourg"

我想过用空格分隔它们,但我找不到任何正则表达式来计算空格。我试过了:

en\s*charge\s*:\s*((.|\n)*)\s*

和类似,但这给了我两个地址,而不是我正在寻找的。任何帮助都将深表感谢。

6 个答案:

答案 0 :(得分:3)

我会做这样的事情:

str = <<EOT
Adresse de prise en charge :                          Adresse d'arrivée :


  rue des capucines                                      rue des tilleuls


  92210       Saint Cloud                                67000            Strasbourg

  Tél.:                                                  Tél.:
EOT

left_addr  = []
right_addr = []

lines = str.squeeze("\n").gsub(':', '').lines.map(&:strip) # => ["Adresse de prise en charge                           Adresse d'arrivée", "rue des capucines                                      rue des tilleuls", "92210       Saint Cloud                                67000            Strasbourg", "Tél.                                                  Tél."]
center_line_pos = lines.max.length / 2 # => 35

lines.each do |l|
  left_addr << l[0 .. (center_line_pos - 1)].strip
  right_addr << l[center_line_pos .. -1].strip
end

此时left_addrright_addr看起来像:

left_addr  # => ["Adresse de prise en charge", "rue des capucines", "92210       Saint Cloud", "Tél."]
right_addr # => ["Adresse d'arrivée", "rue des tilleuls", "67000            Strasbourg", "Tél."]

以下是它们的内容:

puts left_addr
puts '------'
puts right_addr

# >> Adresse de prise en charge
# >> rue des capucines
# >> 92210       Saint Cloud
# >> Tél.
# >> ------
# >> Adresse d'arrivée
# >> rue des tilleuls
# >> 67000            Strasbourg
# >> Tél.

如果您需要结果全部在一行而没有'Tel:':

puts left_addr[0..-2].join(' ').squeeze(' ')
puts '------'
puts right_addr[0..-2].join(' ').squeeze(' ')

# >> Adresse de prise en charge rue des capucines 92210 Saint Cloud
# >> ------
# >> Adresse d'arrivée rue des tilleuls 67000 Strasbourg

以下是对发生情况的细分:

str.squeeze("\n") # => " Adresse de prise en charge :                          Adresse d'arrivée :\n  rue des capucines                                      rue des tilleuls\n  92210       Saint Cloud                                67000            Strasbourg\n  Tél.:                                                  Tél.:\n"
  .gsub(':', '') # => " Adresse de prise en charge                           Adresse d'arrivée \n  rue des capucines                                      rue des tilleuls\n  92210       Saint Cloud                                67000            Strasbourg\n  Tél.                                                  Tél.\n"
  .lines         # => [" Adresse de prise en charge                           Adresse d'arrivée \n", "  rue des capucines                                      rue des tilleuls\n", "  92210       Saint Cloud                                67000            Strasbourg\n", "  Tél.                                                  Tél.\n"]
  .map(&:strip)  # => ["Adresse de prise en charge                           Adresse d'arrivée", "rue des capucines                                      rue des tilleuls", "92210       Saint Cloud                                67000            Strasbourg", "Tél.                                                  Tél."]

答案 1 :(得分:2)

假设每行中的每个地址部分都缩进与第一行中相应的"Adresse"一样多或更远,以下内容不仅可以提取两个对齐的地址,而且通常可以提取n个地址。

lines = string.split(/#{$/}+/)
# => [
# =>   "Adresse de prise en charge :                          Adresse d'arrivée :",
# =>   "  rue des capucines                                      rue des tilleuls",
# =>   "  92210       Saint Cloud                                67000            Strasbourg",
# =>   "  Tél.:                                                  Tél.:"
# => ]

break_points = []
lines.first.scan(/\bAdresse\b/){break_points.push($~.begin(0))}
ranges = break_points.push(0).each_cons(2).map{|s, e| s..(e - 1)}
# => [0..53, 54..-1]

address1, address2 =
lines[1..-2]
.map{|s| ranges.map{|r| s[r]}}
.transpose
.map{|a| a.join(" ").strip.squeeze(" ")}
# => [
# =>   "rue des capucines 92210 Saint Cloud",
# =>   "rue des tilleuls 67000 Strasbourg"
# => ]

答案 2 :(得分:2)

<强>假设

我假设不需要第一行和最后一行,街道名称至少由两个空格分隔,邮政编码/城市字符串相同。这允许“奖金收费”的街道名称(和邮政编码/城市对)在“Adresse d'arrivée:”之后结束。

<强>代码

def parse_text(text)  
  text.split(/\n+\s+/)[1..-2].
       map { |s| s.gsub(/\d+\K\s+/,' ').split(/\s{2,}/) }.
       transpose.
       map { |a| a.join(' ') }
end

<强>实施例

示例1

text = <<BITTER_END
Adresse de prise en charge :                          Adresse d'arrivée :


  rue des capucines                                      rue des tilleuls


  92210       Saint Cloud                                67000            Strasbourg

  Tél.:                                                  Tél.:
BITTER_END


parse_text(text)
  #=> ["rue des capucines 9210 Saint Cloud",
  #    "rue des tileuls 670 Strasbourg"]

示例2

text = <<_
Adresse 1 :                Adresse 2 :                  Adresse 3 :


  rue nom le plus long du monde par un mile  rue gargouilles  rue des tilleuls


  92210           Saint Cloud  31400 Nice              67000     Strasbourg

  France                     France                       France

  Tél.:                      Tél.:                        Tél.:
_

parse_text(text)
  #=> ["rue nom le plus long du monde par un mile 92210 Saint Cloud France",
  #    "rue gargouilles 31400 Nice France",
  #    "rue des tilleuls 67000 Strasbourg France"] 

<强>解释

问题中给出text的步骤:

拆分成行,删除空行和前导空格:

a1 = text.split(/\n+\s+/)
  #=> ["Adresse de prise en charge :                        Adresse d'arrivée :",
  #    "rue des capucines                                    rue des tilleuls",
  #    "92210       Saint Cloud                              67000            Strasbourg",
  #    "Tél.:                                                Tél.:\n"] 

删除第一行和最后一行:

a2 = a1[1..-2]
  #=> ["rue des capucines                                    rue des tilleuls",
  #    "92210       Saint Cloud                              67000            Strasbourg"]

删除邮政编码和城市之间的额外空格,并将每一行拆分为两个或多个空格:

r = /
    \d+  # match one or more digits
    \K   # forget everything matched so far
    \s+  # match one of more spaces
    /x   # extended/free-spacing regex definition mode 

a3 = a2.map { |s| s.gsub(/\d+\K\s+/,' ').split(/\s{2,}/) }
  #=> [["rue des capucines", "rue des tilleuls"],
  #    ["92210 Saint Cloud", "67000 Strasbourg"]] 

按列分组:

a4 = a3.transpose
  #=> [["rue des capucines", "92210 Saint Cloud"],
  #    ["rue des tilleuls", "67000 Strasbourg"]]

加入字符串:

a4.map { |a| a.join(' ') }
  #=> ["rue des capucines 92210 Saint Cloud",
  #    "rue des tilleuls 67000 Strasbourg"] 

答案 3 :(得分:2)

str = 
" Adresse de prise en charge :                          Adresse d'arrivée :


  rue des capucines                                      rue des tilleuls


  92210       Saint Cloud                                67000            Strasbourg

  Tél.:                                                  Tél.:"

adr_prise, adr_arr = str.lines[3].strip.split(/ {2,}/) #split on 2+ spaces
code_prise, cite_prise, code_arr, cite_arr = str.lines[6].strip.split(/ {2,}/)

答案 4 :(得分:1)

受到@steenslag's very pragmatic answer的启发,这是一个非常密集的单行内容,只是为了好玩。

# Assume the input data is in the variable `text`
left_addr, right_addr = text.lines.values_at(3, 6).map do |line|
    line.scan(/(?:\d+  +)?\S+(?: \S+)*/)
        .map {|part| part.squeeze(' ') }
  end
  .transpose
  .map {|addr| addr.join(' ') }

puts left_addr
# => rue des capucines 92210 Saint Cloud
puts right_addr
# => rue des tilleuls 67000 Strasbourg

与@ steenslag的答案一样,这假设所需的数据总是在第3和第6行。它还假设在第6行,两列都有一个邮政编码和城市,邮政编码将始终开始有一个数字。

因为它是一个非常密集的单行,因为它做了很多假设,我不认为这是最好的答案,我将它标记为社区维基。

如果我有时间,我会稍后再回来解压缩。

答案 5 :(得分:0)

假设“中心线位置”已知,这将起作用:

left_lines, right_lines = str.scan(/^(.{50})(.*)$/).transpose

正则表达式在每行的开头捕获50个字符加上剩余的字符,直到行结束。

scan返回一个嵌套数组:(我正在使用占位符,因为实际的行太长了)

[
  ['1st left line', '1st right line'],
  ['2nd left line', '2nd right line'],
  ...
]

transpose将其转换为:

[
  ['1st left line', '2nd left line', ...],    # <- assigned to left_lines
  ['1st right line', '2nd right line', ...]   # <- assigned to right_lines
]

行(不包括第一行和最后一行)必须为join,并且必须删除空格:(请参阅stripsqueeze

left_lines[1..-2].join(' ').strip.squeeze(' ')
#=> "rue des capucines 92210 Saint Cloud"

right_lines相同:

right_lines[1..-2].join(' ').strip.squeeze(' ')
#=> "rue des tilleuls 67000 Strasbourg"