Сортировка строк по тем, которые содержат цифры, игнорируя числа, прикрепленные к букве - PullRequest
3 голосов
/ 23 марта 2012

Сортировка строк по тем, которые содержат числа, игнорируя числа, прикрепленные к букве

Мне нужно отсортировать строки в файле так, чтобы строки содержали хотя бы одно число (0-9), не считая числа 1-5, когда им предшествует одна из этих букв ("a", "e", «g», «i», «n», «o», «r», «u», «v» или «u:» (u + :)) перемещаются в конец файла.

Вот пример файла:

I want to buy some food.
I want 3 chickens.
I have no3 basket for the eggs.
I have no3 basket which can hold 24 eggs.
Move the king to A3.
Can you move the king to a6?

В файле с примерами есть примечания, какие из них соответствуют:

I want to buy some food. % does not match
I want 3 chickens. % matches
I have no3 basket for the eggs. % does not match, because "3" is preceded by "o"
I have no3 basket which can hold 24 eggs. % matches, because contains "24"
Move the king to A3. % matches, words preceded by "A" are not ignored.
Can you move the king to a6? % matches, 6 is not 1-5

В результате все соответствующие строки будут размещены внизу:

I want to buy some food.
I have no3 basket for the eggs.
I want 3 chickens.
Move the king to A3.
Can you move the king to a6?
I have no3 basket which can hold 24 eggs.

Предпочтительно (хотя и не обязательно) решение сортирует строки, содержащие наибольшее количество совпадающих цифр до конца. Например. «У меня 10 кур и 12 летучих мышей». (4 цифры) появляется после «У меня 99 кур». (2 цифры).

Решения, использующие BASH, Perl, Python 2.7, Ruby, sed, awk или grep, хороши.

Ответы [ 7 ]

5 голосов
/ 23 марта 2012

Если ваш grep поддерживает -P (perl-regexp) вариант:

pat='(?<=[^0-9]|^)((?<!u:)(?<![aeginoruv])[1-5]|[06-9])'

{ grep -vP "$pat" input.txt; grep -P "$pat" input.txt; } >output.txt

Если у вас установлено ssed (super sed):

ssed -nR '
/(?<=[^0-9]|^)((?<!u:)(?<![aeginoruv])[1-5]|[06-9])/{
    H
    $!d
}
$!p
${
    g
    s/\n//
    p
}' input.txt
3 голосов
/ 23 марта 2012

Когда эта программа запущена в вашем наборе данных:

#!/usr/bin/env perl    
use strict;
use warnings;

my @moved = ();

my $pat = qr{
      [67890]                   # these big digits anywhere, or else...
    | (?<! [aeginoruv]   )      # none of those letters before
      (?<! u:            )      # nor a "u:" before
      [12345]                   # these little digits
}x;

while (<>) {
    if (/$pat/) {
        push @moved, $_;
    } else {
        print;
    }
}

print @moved;

выдаст желаемый результат:

I want to buy some food.
I want 3 chickens.
I have no3 basket for the eggs.
I have no3 basket which can hold 24 eggs.
Move the king to A3.
Can you move the king to a6?

EDIT

Чтобы включить сортировку, измените окончательный отпечаток на этот:

print for sort {
    $a =~ y/0-9// <=> $b =~ y/0-9//
} @moved;

А теперь вывод будет таким:

I want to buy some food.
I have no3 basket for the eggs.
I want 3 chickens.
Move the king to A3.
Can you move the king to a6?
I have no3 basket which can hold 24 eggs.
1 голос
/ 23 марта 2012

Это может сработать для вас:

sed 'h;s/[aeginoruv][1-5]\|u:[1-5]//g;s/[^0-9]//g;s/^$/0/;G;s/\n/\t/' file |
sort -sn |
sed 's/^[^\t]*\t//'
I want to buy some food.
I have no3 basket for the eggs.
I want 3 chickens.
Move the king to A3.
Can you move the king to a6?
I have no3 basket which can hold 24 eggs.

В основном трехэтапный ход:

  1. Создать числовую клавишу для сортировки выходных данных.Строки, которые не нуждаются в сортировке, получают ключ 0, все остальные имеют числовое значение.
  2. Сортировка по порядку сохранения числовых ключей -s
  3. Удалите числовой ключ.
1 голос
/ 23 марта 2012

рубин

( Редактировать : теперь включает необязательную сортировку)

matches = []
non_matches = []
File.open("lines.txt").each do |line|
  if line.match(/[67890]|(?<![aeginoruv])(?<!u:)[12345]/)
    matches.push line
  else
    non_matches.push line
  end
end
puts non_matches + matches.sort_by{|m| m.scan(/\d/).length}

производит:

I want to buy some food.
I want 3 chickens.
I have no3 basket for the eggs.
Move the king to A3.
Can you move the king to a6?
I have no3 basket which can hold 24 eggs.
1 голос
/ 23 марта 2012
use strict;
use v5.10.1;
my @matches;
my @no_matches;
while (my $line = <DATA>) {
    chomp $line;

    if ($line =~ / \d+\W/) {
        #say "MATCH $line"; 
        push @matches, $line;
    }
    elsif ($line =~ /u:[1-5]+\b/) {
        #say "NOMATCH   $line"; 
        push @no_matches, $line;
    }
    elsif ($line =~ /[^aeginoruv][1-5]+\b/) {
        #say "MATCH $line"; 
        push @matches, $line;
    }
    elsif ($line =~ /.[6-90]/) {
        #say "MATCH $line"; 
        push @matches, $line;
    }
    else {
        #say "NOMATCH   $line";
        push @no_matches, $line;
    }
}

foreach (@no_matches){
    say $_;
}
foreach (@matches){
    say $_;
}

__DATA__
I want to buy some food.
I want 3 chickens.
I have no3 basket for the eggs.
I have no3 basket which can hold 24 eggs.
What is u:34?                              <- custom test 
Move the king to A3.
Can you move the king to a6?

ПОДСКАЗКА> perl regex.pl

I want to buy some food.
I have no3 basket for the eggs.
What is u:34?                              <- custom test
I want 3 chickens.
I have no3 basket which can hold 24 eggs.
Move the king to A3.
Can you move the king to a6?
1 голос
/ 23 марта 2012

[Отредактировано, потому что у всех остальных был код, который принимал аргумент файла:]

Для решения без регулярных выражений в Python, как насчет

import sys

def keyfunc(s):
    ignores = ("a", "e", "g", "i", "n", "o", "r", "u", "v", "u:")
    return sum(c.isdigit() and not (1 <= int(c) <= 5 and s[:i].endswith(ignores)) 
               for i,c in enumerate(s))

with open(sys.argv[1]) as infile:
    for line in sorted(infile, key=keyfunc):
        print line,

, который производит:

I want to buy some food.
I have no3 basket for the eggs.
I want 3 chickens.
Move the king to A3.
Can you move the king to a6?
I have no3 basket which can hold 24 eggs.
I have 99 chickens.
I have 10 chickens and 12 bats.
1 голос
/ 23 марта 2012

Это звучит как работа для Perl!

Серьезно, sed будет бороться с требованием переместить «u:» в конец файла. Sed действительно линейный. Awk может это сделать, но Perl, вероятно, лучше.

Используйте \ d + для сопоставления строки с цифрами

Затем используйте [aeginorv] \ d +, чтобы отфильтровать ваши письма

u: \ d + для обработки вашего специального случая u: stuff (вы должны будете это буферизовать (например, просто хранить совпадающие строки в массиве), чтобы вы могли вывести его в конце)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...