Удалить некоторые символы из строки по индексу (Raku) - PullRequest
15 голосов
/ 26 марта 2020

FAQ: Как в Raku удалить некоторые символы из строки, основываясь на их индексе?

Скажем, я хочу удалить индексы с 1 по 3 и 8

xxx("0123456789", (1..3, 8).flat);  # 045679

Ответы [ 7 ]

14 голосов
/ 26 марта 2020

Вариант ответа Шниперсона:

my $a='0123456789';
with $a {$_=.comb[(^* ∖ (1..3, 8).flat).keys.sort].join};
say $a;

В одной строке:

say '0123456789'.comb[(^* ∖ (1..3, 8).flat).keys.sort].join;

или вызывается функцией:

sub remove($str, $a) {
    $str.comb[(^* ∖ $a.flat).keys.sort].join;
}

say '0123456789'.&remove: (1..3, 8);

или с увеличением Str :

use MONKEY-TYPING;
augment class Str {
    method remove($a) {
        $.comb[(^* ∖ $a.flat).keys.sort].join;
    }
};

say '0123456789'.remove: (1..3, 8);
12 голосов
/ 26 марта 2020
.value.print if .key  !(elem) (1,2,3,8) for '0123456789'.comb.pairs
9 голосов
/ 27 марта 2020

Моя последняя идея для операции not-at (я расскажу о реализации ниже):

Использование:

say '0123456789'[- 1..3, 8 ]; # 045679

Реализация, упаковка (вариант) решения Брэда:

multi postcircumfix:<[- ]> (|args) { remove |args }

sub remove( Str:D $str is copy, +@exdices){
    for @exdices.reverse {
        when Int   { $str.substr-rw($_,1) = '' }
        when Range { $str.substr-rw($_  ) = '' }
    }
    $str
}

say '0123456789'[- 1..3, 8 ]; # 045679

Синтаксис для использования оператора, который я объявил, является string[- list-of-indices-to-be-subtracted ], то есть с использованием знакомой записи [...], но со строкой слева и дополнительным минусом после открытия [ для указывают, что содержимое нижнего индекса представляет собой список exdices , а не indexes .

[Редактировать: я заменил мою первоначальную реализацию на Брэда. Это, вероятно, неправильно, потому что, как отмечает Брэд, его решение «предполагает, что [exdices] находятся в порядке от низшего к высшему, и перекрытия нет», и хотя он не обещает иначе, использование [- ... ] очень близко к этому. Поэтому, если кто-то использует этот синтаксический сахар, он, вероятно, не должен использовать решение Брэда. Возможно, есть способ устранить предположение, которое делает Брэд.]

Мне нравится этот синтаксис, но я знаю, что Ларри намеренно не использует [...] для индексации строк так что, возможно, мой синтаксис здесь не подходит для широкого распространения. Возможно, было бы лучше, если бы использовались некоторые другие символы брекетинга. Но я думаю, что использование простого синтаксиса postcircumfix неплохо.

(я также пытался реализовать прямой вариант [ ... ] для индексации строк точно так же, как для Positional s, но не смог заставить его работать по независящим от меня причинам сегодня вечером. Странно [+ ... ] будет работать для того, чтобы создавать превосходства, но не для того, чтобы делать индексы; для меня это вообще не имеет смысла! В любом случае, я опубликую то, что у меня есть, и считаю этот ответ завершенным.)


[Изменить: Приведенное выше решение имеет два аспекта, которые следует рассматривать как отдельные. Во-первых, пользовательский оператор syntacti c sugar, предоставляемый объявлением postcircumfix:<[- ]> (Str .... Во-вторых, текст этой декларации. Выше я использовал (вариант) решения Брэда. Мой первоначальный ответ ниже.]


Поскольку ваш вопрос сводится к удалению некоторых индексов .comb и повторению join результата, ваш вопрос по сути дубликат ... [Редактировать: неверно, согласно ответу Брэда.]

Что такое быстрый способ отменить выбор элементов массива или списка? добавляет еще больше решений для ответов [.comb ... .join] здесь.


Реализовано как два мультисистема, поэтому один и тот же синтаксис может использоваться с Positional s:

multi postcircumfix:<[- ]> (Str $_, *@exdex) { .comb[- @exdex ].join }

multi postcircumfix:<[- ]> (@pos,   *@exdex) { sort keys ^@pos (-) @exdex } 

say '0123456789'[- 1..3, 8 ]; # 045679

say (0..9)[- 1..3, 8 ];       # (0 4 5 6 7 9)

Реализация sort keys ^@pos (-) @exdices - это лишь слегка упрощенная версия ответа @ Себастьяна. Я не сравнивал его с решением jnthn из предыдущего ответа, который я связал выше, но если это быстрее, его можно заменить. * [Редактировать: Очевидно, что вместо этого должно быть решение Брэда для строкового варианта.] *

8 голосов
/ 26 марта 2020

Это самое близкое, что я получил с точки зрения простоты и краткости.

say '0123456789'.comb[ |(3..6), |(8..*) ].join
8 голосов
/ 26 марта 2020

еще один вариант:

print $_[1] if $_[0] !(elem) (1,2,3,8) for ^Inf Z 0..9;

.print for ((0..9) (-) (1,2,3,8)).keys;
7 голосов
/ 28 марта 2020

Каждый либо превращает строку в список, используя comb, либо использует плоский список индексов.

Нет причин делать что-либо из этого

sub remove( Str:D $str is copy, +@indices ){
    for @indices.reverse {
        when Int   { $str.substr-rw($_,1) = '' }
        when Range { $str.substr-rw($_  ) = '' }
    }
}

remove("0123456789",  1..3, 8 );  # 045679
remove("0123456789", [1..3, 8]);  # 045679

Выше предполагается, что индексы находятся в порядке от низшего к самому высокому, и перекрытия нет.

5 голосов
/ 26 марта 2020
my $string='0123456789';
for (1..3, 8).flat.reverse { $string.substr-rw($_, 1) = '' }
...