2015-08-03 4 views
3

У меня есть двоичное число, например 10000111000011, и вы хотите разбить его на группы последовательных 1s и 0s, 1 0000 111 0000 11.Разделить двоичное число на группы нулей и единиц

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

use strict; 
use warnings; 
use feature 'say'; 

my $bin_string = '10000111000011'; 
my @groups = split /(?<=(\d))(?!\g1)/, $bin_string; 

say "@groups"; 

Однако это приводит к

1 1 0000 0 111 1 0000 0 11 1 

так или иначе, захваченная цифра вставлена ​​в каждом расколе. Что пошло не так?

+0

Вам не нужен 'split'. Попробуйте '@ groups = $ bin_string = ~/1 + | 0 +/g' .. –

+0

Это, конечно, более элегантно! Я все еще хотел понять, что происходит, и, возможно, есть способ спасти регулярное выражение. –

+0

У вас есть свой ответ, но я просто добавлю, что, прочитав это, моя первая мысль была «слишком сложная». 'perl -pe 's/(0+ | 1 +)/\ 1/g' <<<" 10000111000011 "выполняет задание или если вы хотите что-то более обобщенное,' perl -pe 's/((.) \ 2 *)/\ 1/g''. – ghoti

ответ

2

Вот небольшое исправление кода:

my @groups = split /(?<=0(?!0)|1(?!1))/, $bin_string; 

Проблема вы испытываете в том, что при использовании split захваченных текстов также вывода в результирующем массиве. Таким образом, решение состоит в том, чтобы избавиться от группы захвата.

Поскольку у вас есть только 0 или 1 на вашем входе, это довольно легко с чередованием и взглядом, чтобы убедиться, что цифры изменены.

См demo

+1

Хотя все ответы касаются основной проблемы, я выбрал ее так, как она была принята, поскольку она фактически отвечает на вопрос «почему это произошло». Поведение «split» с группами захвата фактически [задокументировано] (http://perldoc.perl.org/functions/split.html). Есть ли конкретная причина, по которой вы выбрали свою скобку, скажем, '(? <= 0) (?! 0) | (? <= 1) (?! 1)'? –

+1

Я выбрал эту группу, потому что я следовал логике чередования: мы разделяли с помощью внешнего вида и внутри, у нас есть 2 альтернативы: 1) нуль, за которым не следует ноль, и 2) один, за которым не следует один. Да, разделение с шаблоном регулярного выражения с группами захвата документируется для языков, где это работает (он не работает на Java) (http://ideone.com/LiwxK6)). –

1

Просто выполните сопоставление вместо разделения.

(\d)\1* 

Пример:

use strict; 
use warnings; 
use feature 'say'; 

my $bin_string = '10000111000011'; 
while($bin_string =~ m/((\d)\2*)/g) { 
    print "$1\n"; 
} 

IDEONE

1
(?<=0)(?=1)|(?<=1)(?=0) 

Просто расщепляются this.See демо.

https://regex101.com/r/fM9lY3/3

The lookarounds будет найти место, где есть 0 позади и 1 впереди или позади 1 и 0 ahead.Thus в результате правильного разделения, не потребляя ничего.

+0

почему downvoted ????????? – vks

+2

Зачем ПП «попробовать это»? Хороший ответ всегда будет объяснять, что было сделано, и почему это было сделано именно так, не только для OP, но и для будущих посетителей SO. –

+1

Cool. Если вам интересно о DV (я не ответил ни на этот, ни на ваш другой ответ), посмотрите, включили ли вы объяснение того, что вы сделали. Особенно, если вы демонстрируете регулярное выражение, вы можете немного поработать и дать подробное объяснение. Новички, приходящие к SO и видящие эти ответы, будут лучше, и на самом деле могут получить понимание решений. –

Смежные вопросы