Добавление метода replaceAll в класс ActionScript String - PullRequest
1 голос
/ 03 ноября 2010

Мне нужна помощь в добавлении замены всех функций в мой проект Flex.Я бы предпочел сделать это настолько естественным, насколько это возможно.

То, чего я хочу достичь, - это возможность запустить этот код (с помощью компилятора Flex) "aabbaaba".replaceAll("b","c") и получить "aaccaaca".Также я хочу связать replaceAll вызовы.
Примечание: на самом деле я не буду заменять b s c s, но различными строками, которые не будут известны во время кодирования!

Чего я не хочу:
1. Используйте регулярные выражения с глобальным флагом.Токены для замены определяются во время выполнения объявления, и преобразование их в регулярное выражение не является прямым.
2. Используйте метод StringUtil.replace.Это статический метод, и цепочка ужасна.
3. Цепочка split и join.Потому что это может сбивать с толку других при чтении кода.
4. Отключите строгую проверку типов.Я хочу иметь проверку типов для остальной части моего кода.


Вот что у меня пока есть:

String.prototype.replaceAll = function(replace:String, replaceWith:String):String{
    return this.split(replace).join(replaceWith);
}

И это можно назвать так:

"aababacaaccb"["replaceAll"]("b", "c")["replaceAll"]("c", "a");

Кроме того, есть лирекомендации против расширения объектов через прототип? Я также приму ответ, в котором есть веские аргументы против расширения объекта String через прототип.

Спасибо,
Алин

Ответы [ 7 ]

7 голосов
/ 03 ноября 2010

Второй ответ таков:

напишите класс-оболочку StringEx для String, и вы можете определить replaceAll, который будет объединен в цепочку следующим образом

public function replaceAll(replace:String, replaceWith:String):StringEx {
   string = string.replace(new RegExp(replace, 'g'), replaceWith);
   return this;
}

, предоставляя toString (), вы можете легко изменить объект StringEx на String

var result:String = "" + new StringEx("aaccaaca").replaceAll('b', 'c').replaceAll('c', 'a');

Вы можете получить полную версию здесь: ООП способ расширения прототипа - сборка флешку wonderfl онлайн

2 голосов
/ 04 ноября 2010

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

Прототипы не рекомендуются для языка ООП, такого как AS3 (в основном потому, что они не поддаются инкапсуляции). Вы подразумеваете, что не хотите, чтобы что-то «сбивало с толку других» (по отношению к split.join); Что ж, прототипы в AS3 очень запутанные. Как пример этого, объявление прототипа может быть сделано из любого места в вашем коде, и поэтому не очевидно, где оно должно находиться. Если «другие» сталкиваются с «foo» .replaceAll () в вашем коде, совершенно не очевидно, где можно найти этот метод и проверить, что он действительно делает.

Статическая функция исправляет это и довольно проста. Конечно, вам нужен дополнительный аргумент, и вы не можете правильно связать, но разве это плохо?

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

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

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

1 голос
/ 03 ноября 2010

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

public class StringUtil {
    public static function replaceAll(source:String,map:Object):String {
        for(var replaceToken:String in map) {
            source = source.split(replaceToken).join(map[replaceToken]);
        }
        return source;
    }
}

var str:String = "a1ccca111a";

str = StringUtil.replaceAll(str,{
    'a' : 'b',
    '1' : '2'
});
trace(str);

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

1 голос
/ 03 ноября 2010

Чего я не хочу: 1. Использовать регулярные выражения с глобальным флагом

Почему бы и нет?для простых замен строк достаточно просто и производительно:

"aababacaaccb".replace(/b/g, "c");

или, если вы предпочитаете:

var needle:String="b";
"aababacaaccb".replace(new RegExp(needle,"g"), "c");

, я бы не рекомендовал использовать для этого прототип, он не очень ООП и не стандартный... он слишком взволнован для такой простой операции.

0 голосов
/ 08 марта 2016

Я знаю, что это старая ветка, но это то, что я придумал, которая может выполнять любую обычную строку

    public static function replaceAll(p_string:String, p_search:String, p_replaceWith:String):String{

    //Dummy Control
        if(p_string == null)
            return '';

    //Iterates through the string from right to left so we don't go over what we are changing.
        var index:int = p_string.lastIndexOf(p_search);
        while(index != -1){

        //Splits the string at the index
            p_string = p_string.slice(0, index) + p_replaceWith + p_string.slice(index+p_search.length);

        //Attempts to find the next index
            index = p_string.lastIndexOf(p_search, index-1);//We -1 so we always move down the line
        }

    //Returns the modified p_string
        return p_string;
    }
0 голосов
/ 03 ноября 2010

У меня есть два ответа для вас. Первым будет то, что вы хотите. Но я рекомендую второй.

Включение прототипов в flex очень просто, и это можно сделать, установив flex-config

ReplaceAllTest.as

package {
    import flash.display.Sprite;
    import flash.text.TextField;
    public class ReplaceAllTest extends Sprite
    {
        public function ReplaceAllTest() 
        {
            var tf:TextField = new TextField;
            String.prototype.replaceAll = function(replace:String, replaceWith:String):String{
                return this.split(replace).join(replaceWith);
            }
            // now the strict mode is off compiler does NOT warn the following code
            tf.text = "aababacaaccb".replaceAll("b", "c")
                                    .replaceAll("c", "a");
            addChild(tf);
        }
    }
}

ReplaceAllTest-config.xml

<?xml version="1.0" encoding="utf-8" ?>
<flex-config>
    <compiler>
       <as3>false</as3>
       <es>true</es>
       <strict>false</strict>
    </compiler>
    <static-link-runtime-shared-libraries>true</static-link-runtime-shared-libraries>
</flex-config>

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

0 голосов
/ 03 ноября 2010

"aabbaaba".split('b').join('c') возвращает 'aaccaaca'

UPD:
Интересно, почему это неприемлемо для вас (однако оно не поддерживает регулярные выражения): оно работает довольно быстро (проверено в серьезных циклах) и делает именно то, что вы хотите.

а также есть пара решений, которые не упомянуты в вашем черном списке (кстати, статическая функция лучше, чем возиться с прототипом - imho):

  • Вы можете расширить класс String только с помощью метода replaceAll и вызова super(). экземпляры этого класса вернут true, если вы отметите (myStringInstance is String)
  • и другое решение: создайте оболочку вместо расширения: класс, который будет хранить строку для вас, предоставляя дополнительную функциональность (хотя я не могу представить ее для строки) и, возможно, делая некоторые из ее свойств доступными только для чтения. или он может иметь только геттер и сеттер для одного
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...