如何更正导致列集中 "shifted" 数据丢失的单元格/缺少分隔符?

How to correct missing cells / missing delimiters causing "shifted" data in sets of columns?

我每行用分号分隔的制造商产品和供应商数据缺少单元格。 电子表格中每个制造商的产品都有多个供应商。

数据的顺序将始终按列排列:

vendor_name_1, vendor_address_1, vendor_phone_1, vendor_fax_1, vendor_contact_mobile_1, vendor_contact_email_1, etc.

当该产品有多个供应商时(几乎所有供应商都是),从左到右的顺序会重复出现另一列:

vendor_name_2, vendor_address_2, vendor_phone_2, vendor_fax_2, vendor_contact_mobile_2, vendor_contact_email_2, etc.

此时,只要该行上的产品有更多供应商,列集就会重复。

"good" 行将在正确的列中包含所有可用数据:

Motion Distributors; 3231 Apex Drive; Dulles, Ohio 45321; (321) 542-6422(p); (321) 542-6428(f); (321) 542-6680(m); alan@motiondist.com; etc. etc.

"bad" 行中至少有一个供应商缺少一件或多件商品,这当然会影响缺失单元格右侧的所有内容,因此所有内容都会移动。

由于单元格中的某些数据丢失,问题是将每行中的数据返回到正确的单元格。

例如,如果缺少 vendor_fax 数字,则该缺失单元格右侧的所有单元格都不会进入正确的列并被移动。

更糟糕的是,由于同一产品有多个供应商,每行缺失的单元格越多,该行发生的移动就越多。

有没有办法解决这个问题,因为每个列集都有相同的排列,只是缺少额外的分隔符?

我希望至少可以通过每个列类型(姓名、phone 号码、电子邮件等)的通用匹配来修复公司和联系人姓名以及 phone 号码?

有没有办法按每一行处理电子表格以确保匹配发生?如有必要,如果允许更具体的匹配,我可以将单元格拆分到其他列中。

我非常渴望使用任何必要的语言或实用程序来解决问题。

我已经在 SO 上搜索了几个类别,但还没有找到解决这个问题的方法...

理想的解决方案是让向您发送此数据的人甚至为空白列吐出一个分隔符,然后您的所有列都会在导入时毫无问题地排列。假设固定输入不是一个选项...

我认为您需要逐列确定输入的每一列中的数据

电子邮件地址很简单 - 其中有一个 @ 和一个 .,否则它们无效。如果您在错误的位置找到一个,请向右移动直到它在电子邮件列中。

缺少 phone 号码也很容易。由于他们似乎有 (p)(f)(m) 来识别号码类型,只需拉出最后三个字符即可识别您拥有的号码。如果您遗漏了一个,请将剩余的向右移动,直到您拥有的那个在正确的列中。

识别邮政编码相当简单,它可以是 5 02134 或 9 位数字 021345678,也可能是 10 个字符 02134-5678。向右移动直到对齐。

如果州被拼写出来,有一个 table 列出所有州,如果您找到比预期更早的匹配项,则向右移动直到州位于正确的位置。如果州是标准的 2 个字符的邮政缩写,只需查找一个 2 个字符的列并向右移动直到匹配。

美国街道地址应该以房屋(或建筑物)号码开头,因此以数字开头的字符串应该是地址,但它可能是一个邮政编码(带嵌入式破折号 - 的 zip+4),因此如果它全部是数字(可能包括破折号),那么它就是邮政编码字段,否则就是地址字段。

城市...好吧,这是一个全 alpha 字段,应该是在整理完所有其余部分后剩下的。

公司名称 - 所有这一切都假定公司名称确实在那里开始记录,如果不是,你可能有点不走运,但我相信有一些方法可以识别那里的内容。

您可能想尝试使用状态机之类的东西。我在记录的这一点上,所以这是我 期望 接下来要找到的,让我们看看下一列数据,看看 实际上是什么 那里,然后向右移动,直到看起来排成一行。这应该最大限度地减少公司名称缺失或城市名称错误识别的错误。

你应该可以用你选择的语言来写,但它可能不是世界上最快的东西,因为它必须一次导入一个字段。

假设 phone 数字之类的格式是可预测的并且易于辨别(即 phone 和传真之间的区别很明显,如您的示例所示)那么应该很容易好好猜测一下字段是如何匹配的。 我会创建一个正则表达式的散列,例如:

field_regexes = { 
  name:    \^.+$\,
  street:  \^d+\s\,
  city:    \^.*,\s\d{5}$\,
  phone:   \^\(\d{3}\)\s\d{3}\-\d{4}\(p\)$\, 
  fax:     \^\(\d{3}\)\s\d{3}\-\d{4}\(f\)$\, 
  mobile:  \^\(\d{3}\)\s\d{3}\-\d{4}\(m\)$\, 
  email:   \^\w+\@\w+.\w+$\,
  etc... 
}

代码可能类似于:

fields = input.split(';').map(&:strip)

while fields.present? do
  record = parse_record(fields) 
  break unless record.present?  # something went wrong
  save(record) 
end

def parse_record(fields)
  result = {}

  field_regexes.each do |name, regex| do
    if fields[0] =~ regex
      result[name] = fields.unshift
      break if fields.empty?
    end
  end

  result
end   

注意:这假定没有应被视为有效数据的冒号(例如,地址或公司名称中的冒号)