Разбор текста в поисках данных с различными строками, выражающими основные единицы измерения (например, квадратные метры, кв.м, м^2, м2 и т. д.)

Я пытаюсь очистить номер площади (квадратные метры или квадратные футы) многих жилых домов, которые хранятся в различных текстовых файлах.

Площадь почти всегда выражается путем указания единиц либо в метрической системе (длина выражается в метрах в качестве базовой единицы), либо в имперской системе Великобритании (длина выражается в футах в качестве базовой единицы) путем указания числа, за которым следуют единицы.

Единицы площади имеют различные строковые представления, например, «квадратные метры» могут отображаться как «кв.м», «кв.м», «кв.м», «квадрат.м», «кв.метры», «м^2», « m2" и т. д. (также может меняться заглавная буква).

Некоторые примеры TXT, которые у меня есть (я скопировал только строку с интересующими меня данными, очистив остальные):

1)

...
Approximate Gross Internal Area = 40.1 sq m / 432 sq ft Re’
...

2)

...
Total area: approx. 37.3 sq. metres (402.0 sq. feet)
...

3)

...
Approx. Gross Internal Area *
413Ft’-38.37M’
...

Моя цель - проанализировать каждый текстовый файл, получить число квадратных метров (или квадратных футов) и сохранить его.

Я начал изучать инструменты Python Regular Expressions/RegEx, сопоставления с образцом, обработки текста и анализа текста, но решил приостановить исследование и посмотреть, не преследовал ли кто-нибудь еще подобную цель.

Какой, на ваш взгляд, наиболее эффективный способ решения данной конкретной задачи? Используя RegEx, анализ текста или что?

Я вполне готов использовать другие языки сценариев (PERL, Ruby и т. д.), если они больше подходят для этого.


person SergeGardien    schedule 18.09.2015    source источник
comment
Ваш вопрос не ясен: единственное требование, которое вы предъявляете, - это необходимость либо построить синтаксический анализатор, либо использовать регулярное выражение. И то и другое можно сделать на большинстве языков программирования. Пожалуйста, сфокусируйте свой вопрос!   -  person Nir Alfasi    schedule 19.09.2015
comment
В этом вопросе слишком много несвязанной информации. Все упоминания об OCR и текстовых файлах совершенно излишни. Вы должны сократить и перефразировать свой вопрос, чтобы было ясно, что вам нужно проанализировать различные строковые представления площади, и привести несколько конкретных примеров вариантов. Иногда регулярное выражение работает просто отлично, иногда парсер подходит лучше.   -  person angularsen    schedule 19.09.2015
comment
alfasin, это часть того, о чем я прошу: лучше использовать регулярное выражение, парсер или что-то еще? Спасибо, andjdreas, я отредактировал, как вы предложили (кроме того, что сделал его короче).   -  person SergeGardien    schedule 19.09.2015


Ответы (4)


Если я вас правильно понял, вы хотите создать анализатор текста, который выполняет вставки в базу данных (я полагаю).

Я думаю, что это простая задача, и ее можно реализовать на всех предложенных вами языках. Особого выигрыша среди них нет (кроме вопроса предпочтения).

Я предлагаю вам принять язык, следуя этим критериям:

  1. Доступен ли интерпретатор на вашем рабочем сервере?
  2. Do you intend to nurse this code forever or do you intend someone else take care of it in a near future?
    • You
      • Choose the language you feel more comfortable with
    • Someone else
      • Choose a language that are easier to find workers in your area.

Кстати, я бы выбрал Python. Он легко доступен везде.

person David Rissato Cruz    schedule 18.09.2015
comment
Спасибо Давид за ответ. Чтобы ответить на ваши вопросы: 1. Мой рабочий сервер будет моим ноутбуком и R, который настраивается с помощью Python (и, возможно, других языков) 2. Это личный проект, поэтому я буду заботиться об этом. Как и вы, я бы предпочел Python также из-за доступных наборов инструментов для научных вычислений на случай, если я захочу заменить R в целом для этого проекта. - person SergeGardien; 19.09.2015

Вы можете использовать Marpa::R2, интерфейс Perl для Marpa, общий парсер BNF.

Данные могут быть описаны в BNF как this ::= that (оператор ~ определяет лексические правила ).

Парсер возвращает структуру данных (массив массивов в формате [ id, child1, child2 ... ]), из которой можно извлечь области.

Вы также можете определить семантические действия как действия Perl sub. в том же или отдельном пакете для обработки данных.

Ниже приведен пример скрипта и его вывод на основе ваших данных.

сценарий:

use 5.010;
use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Deepcopy = 1;

use Marpa::R2;

my $g = Marpa::R2::Scanless::G->new( { source => \(<<'END_OF_SOURCE'),

    :default ::= action => [ name, value]
    lexeme default = action => [ name, value] latm => 1

    <area data>      ::= <area data item>+
    <area data item> ::= area
    <area>           ::= float unit

    float ~ int '.' int
    float ~ int '.'
    float ~ int
    int ~ [\d]+

    unit ~ 'sqm' | 'sq.m' | 'sq m' | 'square m' | 'sq.meters' | 'm^2' | 'm2'

    :discard ~ whitespace
    whitespace ~ [\s]+

END_OF_SOURCE
} );

my $input = <<EOI;
40.2 sq m
40 sqm
40. sq.m
40.2 sq m
40.2 square m
40.2 sq.meters
40.2 m^2
40.2 m2
EOI

say Dumper ${ $g->parse( \$input ) };

выход:

[
  'area data',
  [
    'area data item',
    [
      'area',
      [
        'float',
        '40.2'
      ],
      [
        'unit',
        'sq m'
      ]
    ]
  ],
  [
    'area data item',
    [
      'area',
      [
        'float',
        '40'
      ],
      [
        'unit',
        'sqm'
      ]
    ]
  ],
  [
    'area data item',
    [
      'area',
      [
        'float',
        '40.'
      ],
      [
        'unit',
        'sq.m'
      ]
    ]
  ],
  [
    'area data item',
    [
      'area',
      [
        'float',
        '40.2'
      ],
      [
        'unit',
        'sq m'
      ]
    ]
  ],
  [
    'area data item',
    [
      'area',
      [
        'float',
        '40.2'
      ],
      [
        'unit',
        'square m'
      ]
    ]
  ],
  [
    'area data item',
    [
      'area',
      [
        'float',
        '40.2'
      ],
      [
        'unit',
        'sq.meters'
      ]
    ]
  ],
  [
    'area data item',
    [
      'area',
      [
        'float',
        '40.2'
      ],
      [
        'unit',
        'm^2'
      ]
    ]
  ],
  [
    'area data item',
    [
      'area',
      [
        'float',
        '40.2'
      ],
      [
        'unit',
        'm2'
      ]
    ]
  ]
]

Однако в использовании регулярных выражений нет ничего плохого. Они доступны на всех упомянутых вами языках.

BNF может быть более удобочитаемым/поддерживаемым, что хорошо при работе с неструктурированным текстом.

person rns    schedule 19.09.2015
comment
Большое спасибо за ответ rns. Я начну с регулярного выражения, и, если этого решения недостаточно для решения этой задачи, я попробую другое решение, включая BNF Parser. - person SergeGardien; 19.09.2015

Этот ответ был запрошен OP по электронной почте.

Если вы можете использовать библиотеки .NET через IronPython или подобное, вы можете найти применение в Units.NET. для анализа строк вашей области. Или просто скопируйте его регулярное выражение для синтаксического анализа и измените в соответствии с вашими потребностями.

Units.NET может анализировать строковые представления «значение + единица измерения» для большинства часто используемых единиц измерения, как метрических, так и имперских.

Примеры:

double a = Area.Parse("5 m²").SquareMeters; // 5.0
Area.Parse("0.092903m²").SquareFeet;        // ~1.0
Area.Parse("50000 cm²").ToString();         // "5 m²", sq.m is default unit
Area.Parse("1ft²").SquareMeters;            // 0.092903
Area.Parse("1 in²").SquareCentimeters;      // 6.4516

Все единицы площади и их сокращения. Обратите внимание, что SquareMeter в настоящее время поддерживает только "m²", но вы можете добавить дополнительные сокращения, такие как "m^2", "sq.m", "sqm" и т. д., во время выполнения через UnitSystem.MapUnitToAbbreviation(), и мы с радостью принимаем запросы на включение, чтобы добавить в библиотеку дополнительные сокращения единиц измерения. См. пример.

person angularsen    schedule 19.09.2015
comment
Большое спасибо за ответ andjdreas. Судя по вашим ответам и ответам других людей, я предполагаю, что регулярного выражения или синтаксического анализатора будет достаточно для решения этой задачи, поэтому я начну с того, что сначала попробую это решение и посмотрю, работает ли оно, прежде чем углубляться в Units.NET. - person SergeGardien; 19.09.2015
comment
Да, регулярное выражение универсально доступно на большинстве языков. Я бы начал с этого и перешел к синтаксическому анализатору, если регулярное выражение станет слишком громоздким или медленным. Вы можете использовать регулярное выражение Units.NET в качестве отправной точки для вдохновения. - person angularsen; 19.09.2015

Вот код Python RegEx, который я написал для решения проблемы, если он кому-то понадобится:

unit_pattern = re.compile(r"[+-]? *((?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?)\s*(square meters|square metres|square meter|square metre|square m|square mt|sqmt|sq mt|sq.mt|sq. mt|sqm|sq m|sq.m|sq. m|meters2|metres2|meter2|metre2|mt2|m2)", re.IGNORECASE)
for i, line in enumerate(open('/Users/USERNAME/text.txt')):
    for match in re.finditer(unit_pattern, line):
        print 'Found on line %s: %s' % (i+1, match.groups())

Применяется к следующему текстовому файлу:

eleventh Floor
Approx. 37.3 sq. metres (402.0 sq. feet)

Living
Room

7.06m x 4.04m
(23'2" x 13'3")

Bedroom
Area

Shower
Room

Total area: approx. 37.3 sq. metres (402.0 sq. feet)

For illustrative purposes only — Not to scale.
Plan produced using P|anUp.

Дает следующий вывод:

Found on line 2: ('37.3', 'sq. m')
Found on line 16: ('37.3', 'sq. m')
person SergeGardien    schedule 20.09.2015