Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Помогите составить регулярку для получения "private" переменных (https://javascript.ru/forum/misc/36745-pomogite-sostavit-regulyarku-dlya-polucheniya-private-peremennykh.html)

yngwie19 26.03.2013 12:03

Помогите составить регулярку для получения "private" переменных
 
Короче решил немного по-извращаться с кодом. Есть такой код:

(function () {
       MYAPP.widget = function(oData) { 

          if (oData) {
            for(var sKey in oData) {
              this.setData(sKey, oData[sKey]);
            }       
          }
        };

        MYAPP.widget.prototype =  {
          _oData: {},

           getData : function(sField) {
              if (sField) {
                 return this._oData[sField];
            } else {
               return this._oData;
            }
        },  
        
        _privateMethod: function () {
           var text = '_that_dont_get';
        },
        
        setData : function(sKey, value) {
           this._oData[sKey] = value;
           
           console.log("this._oData[sKey]");
        }
       }
    }())


Мне нужно составить регулярное выражение для получения всех переменных и методов, начинающихся с _ , т.е в данном случае это_oData и _privateMethod

Составил такую регулярку:

(\_[a-zA-Z0-9\_]+)


Но она мне помимо нужных мне переменных возвращает и значения, которые находятся в строках.

Подскажите как можно безопасно получить только переменные, может есть уже готовые решения?

danik.js 26.03.2013 12:36

Цитата:

Сообщение от yngwie19
Подскажите как можно безопасно получить только переменные, может есть уже готовые решения?

Тебе нужен парсер javascript-кода, который бы построил AST. Пройдешься потом по дереву и вытянешь нужные переменные. Можешь заюзать «jison»

megaupload 26.03.2013 13:01

тред не читал сразу отвечал
obj = {public:11, _private:12};

for (key in obj) if( key.indexOf('_') ) {
    alert(key)
}

yngwie19 26.03.2013 13:03

danik.js Спасибо за ответ. Допустим переменные я вытяну, скажите а как мне теперь заменить эти переменные скажем на какое-нибудь другое произвольное имя. Как сделать так, чтобы при замене не попала строка console.log("this._oData[sKey]"); ?

rgl 26.03.2013 13:24

var tmp, res = [],
  re = /(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')|(\b_\w*)/g;

while( tmp = re.exec( s ) )
  if( tmp[1] )
    res.push( tmp[1] );

rgl 26.03.2013 13:33

Цитата:

Сообщение от yngwie19 (Сообщение 242700)
как мне теперь заменить эти переменные скажем на какое-нибудь другое произвольное имя. Как сделать так, чтобы при замене не попала строка console.log("this._oData[sKey]"); ?

var re = /(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')|(\b_\w*)/g;
s2 = s.replace( re, function( t1, t2 ) { return t2 ? "new"+t2 : t1 } );

yngwie19 26.03.2013 13:34

rgl Возвращает "'_that_dont_get'" и ""this._dontget1"". Это строки поэтому их не надо

rgl 26.03.2013 13:42

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

yngwie19 26.03.2013 13:59

rgl Объясните пожалуйста, что делает первая часть
(?:"(?:\\.|[^"])*"|'(?:\\.|[^'])*')

rgl 26.03.2013 14:12

Как найти что-то, но не найти его, если оно внутри кавычек? Очень просто, нужно сначала найти все, что в кавычках, и тогда оно будет исключено из дальнейшего поиска.
Как найти то, что в кавычках? Найти открывающую кавычку, найти все что угодно, но только не кавычку, найти закрывающую кавычку.
В результате получаем "[^"]*" У этого выражения есть один недостаток - оно замаскированную кавычку по ошибке примет за закрывающую. Чтобы этого не произошло, придется его слегка усложнить:
"(\\.|[^"])*" - т.е. либо не-кавычка, либо замаскированный любой символ (в т.ч. возможно и кавычка). (Порядок тут важен, сначала замаскированноечтоугодно, а потом - не кавычка, менять нельзя) Чтобы результат в скобочках не "захватывался", добавляем вопрос с двоеточием
"(?:\\.|[^"])*"
Потом все то же самое повторяем с одинарными кавычками
Далее, когда мы нашли нечто, мы нашли либо что-то в кавычках, либо имя переменной, начинающееся с подчерка. Надо отделить одно от другого, проще всего проверить, пустая строка или нет в скобочках (тех, что без вопроса-двоеточия).
Вот и все.

yngwie19 26.03.2013 14:36

rgl, Спасибо Вам большое за решение, подскажите есть ли еще какие-нибудь подводные камни вроде строк: ?
console.log("this._oData[sKey]");
Мне нужно заменить только реальные свойства и методы

danik.js 26.03.2013 15:49

this['_oData']

Это тоже будет заменено или нет?

yngwie19 26.03.2013 15:57

Нет это менять не надо, думаю так правильно использовать. Поправьте пожалуйста регулярку :)

rgl 26.03.2013 15:58

Цитата:

Сообщение от yngwie19 (Сообщение 242719)
подскажите есть ли еще какие-нибудь подводные камни вроде строк: ?
console.log("this._oData[sKey]");
Мне нужно заменить только реальные свойства и методы

Цитата:

Сообщение от danik.js (Сообщение 242728)
this['_oData']

Это тоже будет заменено или нет?

Составить безупречную регулярку очень сложно, и она будет большая и запутанная. Классики (напр. Jeffrey Friedl) учат нас искать компромисс между безупречностью и простотой.
Мое выражение споткнется, напр. на такой строке:
/* this isn't good */ _test = 0; console.log( '_test = 0' );

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

rgl 26.03.2013 16:03

Цитата:

Сообщение от danik.js (Сообщение 242728)
this['_oData']

Это тоже будет заменено или нет?

Это вообще не решаемо, т.к., если пойти дальше тем же путем, то следующим будет вопрос:
var i = '_oData';
// несколько строчек кода
this[i];

yngwie19 26.03.2013 16:08

rgl, можем ли с Вам пообщаться в каком-нибудь чате, у меня есть пара вопросов :)
Например: http://learn.javascript.ru/chat мой ник тот же

rgl 26.03.2013 16:18

Поправлено с учетом возможный комментариев:
var re = /(?:(?:\/\/.*)|(?:\/\*[\s\S]*?\*\/)|"(?:\\.|[^"])*"|'(?:\\.|[^'])*')|(\b_\w*)/g;

rgl 26.03.2013 16:23

Нет, в чате общаться не получается. А чем форум плох? Много читателей снижают вероятность, что какая-то ошибка останется незамеченной.

kobezzza 26.03.2013 16:48

Цитата:

Сообщение от rgl (Сообщение 242715)
Как найти что-то, но не найти его, если оно внутри кавычек? Очень просто, нужно сначала найти все, что в кавычках, и тогда оно будет исключено из дальнейшего поиска.
Как найти то, что в кавычках? Найти открывающую кавычку, найти все что угодно, но только не кавычку, найти закрывающую кавычку.
В результате получаем "[^"]*" У этого выражения есть один недостаток - оно замаскированную кавычку по ошибке примет за закрывающую. Чтобы этого не произошло, придется его слегка усложнить:
"(\\.|[^"])*" - т.е. либо не-кавычка, либо замаскированный любой символ (в т.ч. возможно и кавычка). (Порядок тут важен, сначала замаскированноечтоугодно, а потом - не кавычка, менять нельзя) Чтобы результат в скобочках не "захватывался", добавляем вопрос с двоеточием
"(?:\\.|[^"])*"
Потом все то же самое повторяем с одинарными кавычками

/(["'])(?:\1|.*?[^\\]\1)/g - сразу учитываются одинарные и двойные кавычки (применяются ссылки на подстроки \1), ложные кавычки тоже

ЗЫ: вот так у меня сделано в парсере моего шаблонизатора
/**
 * Заметить кавычки с содержимом в строке на ссылку:
 * __SNAKESKIN_QUOT__номер
 *
 * @private
 * @param {string} str - исходная строка
 * @param {Array=} [opt_stack] - массив для подстрок
 * @return {string}
 */
Snakeskin._escape = function (str, opt_stack) {
	return str.replace(/(["'])(?:\1|.*?[^\\]\1)/g, function (sstr) {
		if (opt_stack) {
			opt_stack.push(sstr);
		}

		return '__SNAKESKIN_QUOT__' + (opt_stack ? opt_stack.length - 1 : '_');
	});
};

/**
 * Заметить __SNAKESKIN_QUOT__номер в строке на реальное содержимое
 *
 * @private
 * @param {string} str - исходная строка
 * @param {!Array} stack - массив c подстроками
 * @return {string}
 */
Snakeskin._uescape = function (str, stack) {
	return str.replace(/__SNAKESKIN_QUOT__(\d+)/g, function (sstr, pos) {
		return stack[pos];
	});
};

rgl 26.03.2013 17:05

Цитата:

Сообщение от kobezzza
/(["'])(?:\1|.*?[^\\]\1)/g - сразу учитываются одинарные и двойные кавычки (применяются ссылки на подстроки \1), ложные кавычки тоже

Споткнется (не заметит закрывающую кавычку) если перед ней стоит замаскированный обратный слэш, напр.
var s = "abcd\\";

kobezzza 26.03.2013 17:16

Цитата:

Сообщение от rgl (Сообщение 242758)
Споткнется (не заметит закрывающую кавычку) если перед ней стоит замаскированный обратный слэш, напр.
var s = "abcd\\";

Добавлю проверку, пасиб за замечание.

(["'])(?:\1|.*?(?:[\\]{2}|[^\\])\1)

rgl 26.03.2013 17:40

kobezzza,
Цитата:

Сообщение от kobezzza
(["'])(?:\1|.*(?:[\\]{2}|[^\\])\1)

a='aaa';b='bbb';
Мой вариант:
(["'])(?:\\.|(?:(?!\1).)*\1)

kobezzza 26.03.2013 17:52

Цитата:

Сообщение от rgl (Сообщение 242767)
kobezzza,

a='aaa';b='bbb';
Мой вариант:
(["'])(?:\\.|(?:(?!\1).)*\1)

Забыл жадность убрать, теперь не спотыкается (обновил выше). Чёт ты перемудрил по-моему:)

var a = '\a':
у тебя упадёт, из-за странной проверки \\.
var a= 'sdsd\'
также упадёт

rgl 26.03.2013 18:13

Не, ну как только я начинаю проверять регэкспы, рискую нарваться :-)
a='aaa\\\'a';b='bbb';

Цитата:

Сообщение от kobezzza
Забыл жадность убрать, теперь не спотыкается (обновил выше).

Цитата:

Сообщение от kobezzza
(["'])(?:\1|.*?(?:[\\]{2}|[^\\])\1)

А я не перемудрил, а недомудрил, вот как надо:
(["'])(?:\\.|(?:(?:(?!\1).)))*\1

rgl 26.03.2013 18:19

Цитата:

Сообщение от kobezzza
у тебя упадёт, из-за странной проверки \\.

Мой первоначальный вариант не работает из-за того, что \1 который должен матчить закрывающую кавычку, находится в скобках, и не применим к первой части | , кроме того, звездочка на левую часть | не действует.
А насчет var a= 'sdsd\' так я предполагаю, что JS-ных ошибок нет, т.е. все кавычки в строке закрываются

kobezzza 26.03.2013 18:36

var a= '\\\' :)

UPD:
не прочитал, что ты не учитываешь этот фактор, тада всё ок.

rgl 26.03.2013 18:50

Цитата:

Сообщение от kobezzza
var a= '\\\'

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

kobezzza 26.03.2013 18:52

Цитата:

Сообщение от rgl (Сообщение 242792)
Ну так твое тоже ошибается.
Раз уж устроили тут такое соревнование-блиц, нужно договориться о правилах, напр, допустимы ли непарные кавычки в строчке. Я изначально считал, что применяться регэксп будет к JavaScript коду, в котором нет ошибок (так тема начиналась), а значит кавычки должны обязательно закрываться.

Да ладно, какие соревнования) Мой тоже падает, думаю, как сделать чтобы не падал:)

rgl 26.03.2013 18:56

Вот при корректном JavaScript кода мой работает правильно, а твой ошибается:
var a= 'a\\\'a';

rgl 26.03.2013 19:00

Цитата:

Сообщение от kobezzza
думаю, как сделать чтобы не падал

Наверно, так:
/(?:"(?:\\.|[^"\\])*"|'(?:\\.|[^'\\])*')/

но тут одинарная и двойная кавычки каждая сама по себе, а тебе хочется чтобы вместе.

rgl 26.03.2013 19:04

Кажется, добил таки:
(["'])(?:\\.|(?:(?:(?!\1|\\).)))*\1

Уф-ф-ф, хорошо поразминался, а то уже подзабывать начал :-)

rgl 26.03.2013 19:35

Убрал лишние скобки:
(["'])(?:\\.|(?:(?!\1|\\).))*\1

kobezzza 26.03.2013 20:12

Цитата:

Сообщение от rgl (Сообщение 242798)
Убрал лишние скобки:
(["'])(?:\\.|(?:(?!\1|\\).))*\1

Респект:)

Цитата:

Уф-ф-ф, хорошо поразминался, а то уже подзабывать начал :-)
+1

devote 26.03.2013 21:39

Цитата:

Сообщение от rgl
Убрал лишние скобки:
(["'])(?:\\.|(?:(?!\1|\\).))*\1

не корректная у вас рега сударь, на моих примерах валится:

вот я вырезал регу со своего скрипта: https://github.com/devote/QSA/blob/master/qsa.js
var re = /(?:(['"])\1|(['"])(?:\\\\|[\s\S])*?(?:\\\\(?=\2)|[^\\])\2)/g;

var testText = 'привет "МИР"! тут я поставлю кавычку " а можно и слеши \\ или кавычка со слешами \\\" или кавычки " " или много слешей и ковычка \\\\\\\\\\\\\\\\" и" т.\\\\\\\\\\\\\\\\\\"д"......';

alert(testText.match(re).join("\n")); // выведет четыре подстроки

// ищем в коде все строки:
var code = "// for Internet Explorer VisualBasic Script accessors\
if (type !== 3) {\
    // create getter in VB Class\
    staticClassParts.push(\
        'Public ' + (type === 4 ? 'Default ' : '' ) + 'Property Get [' + subName + ']',\
        'Call VBCorrectVal(' + ( value && ( type !== 1 || value.get) ?\
            '[(accessors)].[' + prop + ']' + (type === 1 ? '.get' : '') +\
                '.call(me,[(accessors)].[' + prop + '])' : 'window.undefined' ) +\
            ',[' + subName + '])', 'End Property'\
    );\
}\
if (type !== 2) {\
    // create setter in VB Class\
    staticClassParts.push(\
        'Public Property Let [' + subName + '](val)',\
        type = (type === 4 ? 'Set [(accessors)].[' + prop + ']=val' :\
            value && (type !== 1 || value.set) ?\
                'Call [(accessors)].[' + prop + ']' + (type === 1 ? '.set' : '') +\
                    '.call(me,val,[(accessors)].[' + prop + '])' : '') +\
            '\nEnd Property', 'Public Property Set [' + subName + '](val)', type\
    );\
}";

alert(code.match(re).join("\n")); // выведет все найденные строки

Пользовательский тест:
var re = /(?:(['"])\1|(['"])(?:\\\\|[\s\S])*?(?:\\\\(?=\2)|[^\\])\2)/g;
var str = prompt('Введите строку') || '';
var res = str.match(re);
alert("Найдено: " + (res&&res.length||0) + " вхождени(е/й/я)\n--------------------------\n" + (res||[]).join("\n"));


Если нужно парсить код, то для начала, нужно удалить из кода все комменты, а потом искать строки.. Ну и про регулярки не забывать, в них тоже кавычки могут встретится:
<textarea id="area" style="width: 860px; height: 130px;" placeholder="вставь сюда JavaScript код и нажми кнопку process"></textarea>
<button onclick="process()">process</button>
<script>
    function process() {
        var rRemoveCommentsAndRexExp = /((['"])\2|(['"])(?:\\\\|[\s\S])*?(?:\\\\(?=\3)|[^\\])\3)|\/\*[\S\s]*?\*\/|\/[^\/](?:\\\\|[\s\S])*?(?:\\\\(?=\/)|[^\\])\/|\/\/[^\n]*/g;
        var rSearchStrings = /(?:(['"])\1|(['"])(?:\\\\|[\s\S])*?(?:\\\\(?=\2)|[^\\])\2)/g;
        var value = document.getElementById('area').value;
        var str = value.replace(rRemoveCommentsAndRexExp, '$1');
        var res = str.match(rSearchStrings);
        alert("Найдено: " + (res&&res.length||0) + " вхождени(е/й/я)\n--------------------------\n" + (res||[]).join("\n"));
    }
</script>

devote 26.03.2013 21:50

поправил выше код, со слешами не правильно работала рега. Терь гуд

rgl 27.03.2013 10:23

Цитата:

Сообщение от devote
не корректная у вас рега сударь, на моих примерах валится:

Что конкретно не так? Пример строки, и что по вашему мнению нужно найти. В вашем примере находит 4 подстроки, как и надо, т.е. все работает правильно.

devote 27.03.2013 10:26

Цитата:

Сообщение от rgl
Что конкретно не так?

вы проверьте сами
Цитата:

Сообщение от rgl
В вашем примере находит 4 подстроки, как и надо, т.е. все работает правильно.

ну дык я бы и не выкладывал бы свой пример, если бы он не работал

rgl 27.03.2013 10:40

Что не так??
var testText = 'привет "МИР"! тут я поставлю кавычку " а можно и слеши \\ или кавычка со слешами \\\" или кавычки " " или много слешей и ковычка \\\\\\\\\\\\\\\\" и" т.\\\\\\\\\\\\\\\\\\"д"......';
var re = /(["'])(?:\\.|(?:(?!\1|\\).))*\1/g;
alert( testText.match(re).join("\n") );

devote 27.03.2013 11:02

Цитата:

Сообщение от rgl
Что не так??

var str = 'привет "МИР"! тут я поставлю кавычку " а можно и\n слеши \\ или кавычка со слешами \\" или кавычки " " или много\n слешей и ковычка \\\\\\\\\\\\\\\\" и" т.\\\\\\\\\\\\\\\\\\"д"......';

var re = /(["'])(?:\\.|(?:(?!\1|\\).))*\1/g;
var res = str.match(re);
alert("Найдено: " + (res&&res.length||0) + " вхождени(е/й/я)\n--------------------------\n" + (res||[]).join("\n"));


// ----------
var re = /(?:(['"])\1|(['"])(?:\\\\|[\s\S])*?(?:\\\\(?=\2)|[^\\])\2)/g;
var res = str.match(re);
alert("Найдено: " + (res&&res.length||0) + " вхождени(е/й/я)\n--------------------------\n" + (res||[]).join("\n"));

rgl 27.03.2013 11:04

А вот ваша рега как раз ошибается, находит там, где находить не должна (ошибочно замаскированную кавычку принимает за закрывающую):
var testText = "a'b\\\\\\'c"
var re = /(?:(['"])\1|(['"])(?:\\\\|[\s\S])*?(?:\\\\(?=\2)|[^\\])\2)/g;
alert( testText.match(re).join("\n") );


Часовой пояс GMT +3, время: 06:47.