#coldfusion #cfml
#холодное слияние #cfml #coldfusion
Вопрос:
У меня есть такая строка, которую я получаю из базы данных:
user=me@example.comamp;name=John
Я хотел бы знать, есть ли простой способ извлечь данные и поместить их в две переменные, user и name.
Комментарии:
1. Вы можете использовать регулярное выражение или посмотреть
SpanExcluding
в паре с другими строковыми функциями. helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions /…2. Обрабатывайте строку как вложенные списки. Внешний список был бы разделен
amp;
символом, а внутренний —=
символом.3. Поскольку это, по-видимому, строка параметра URL, вы кодируете или очищаете ее перед вставкой в базу данных? Или он хранится точно так же, как описано выше?
4. Что сказал @Shawn. Это очень простой способ для кого-то атаковать ваш сайт.
Ответ №1:
@Marc, согласно предложению @Dan Bracuk, вы можете разделить свою строку, используя упомянутый разделитель сначала как amp;
и снова как =
. Пожалуйста, обратитесь к моему приведенному ниже коду, который вам поможет. Я надеюсь.
<cfset yourInput= 'user=me@example.comamp;name=John'>
<!--- Get the first value. I mean "user" part --->
<cfset splitFirstPart = listfirst(yourInput,'amp;', true)>
<cfset splitLastPart = listlast(yourInput, 'amp;', true)>
<!--- Get the second part value --->
<!--- Above values are split by using amp; --->
<cfset user = listlast(splitFirstPart, '=', true)>
<Cfset name = listlast(splitLastPart, '=', true)>
<!---
Now we can again split the list by using =.
Now you can see the result.
--->
<cfoutput>
User : #user# <br/>
Name : #name#
</cfoutput>
Если вам нужны какие-либо другие функции CFML и разъяснения, пожалуйста, обратитесь кhttps://cfdocs.org /
Спасибо.
Комментарии:
1. Одна вещь, на которую следует обратить внимание, — это то, что
listLast()
вернет первый элемент, если значение параметра пустое. Напримерamp;name=(blank)
. Чтобы сделать код более надежным, рассмотрите возможность использования вместо негоgetToken()
функции. @MarcElBichon — Кроме того, вы могли бы легко превратить приведенный выше код в повторно используемую функцию, которая разбивает любую строку запроса и возвращает структуру параметров и значений2. Да @ageax. Затем вы можете использовать атрибут includeEmptyValues в listlast (). Например, listlast(splitFirstPart,’=’,true). Тогда он вернет только user = » (пустой). Пожалуйста, проверьте это.
3. Верно. Большинство функций списка так долго не поддерживали этот атрибут, что я все время забываю, что они, наконец, «исправили» их! Надеюсь, вы не возражаете, что я добавил ваше предложение в приведенный выше код, так как есть большая вероятность, что параметры URL могут быть пустыми 🙂 Если вам это не нравится, не стесняйтесь откатить его назад.
4. Я надеюсь, что все функции списка поддерживают атрибут includeEmptyValues. Особенно служба поддержки listfirst amp; last. Я перепроверяю это. Спасибо за ваши изменения в моих комментариях. @ageax.
5. Спасибо за ваше время @Ageax
Ответ №2:
Вот мой взгляд на то, как решить эту проблему.
Мне нравится иметь структуру в качестве конечного результата. Мне также нравится работать с каждой функцией как с неявным циклом.
<cfscript>
yourInput= 'user=me@example.comamp;name=John';
variables.result = {};
ListEach(yourInput,
function(item) { variables.result[listfirst(item, "=")] = listLast(item, "="); },
"amp;");
writedump(result);
</cfscript>
Комментарии:
1. Красиво и лаконично. Единственное улучшение, которое я бы предложил, — это использовать
includeEmptyElements=true
, если значение пустое, поэтому функции списка не возвращают «имя» вместо «значения».
Ответ №3:
Чтобы добавить к этому ответу для будущих читателей, есть несколько способов сделать это более динамичным.
По сути, вы просто дважды анализируете список с разделителями и извлекаете нужные вам фрагменты. ColdFusion позволяет несколькими способами сделать это.
Для иллюстрации я добавил к исходной строке.
string="user=me@example.comamp;name=Johnamp;somethingelse=42amp;fooamp;base64Msg=QmVFeGNlbGxlbnRUb0VhY2hPdGhlcg==" ;
Мой предпочтительный способ проанализировать это — использовать функцию CF, которая возвращает структуру всех необходимых мне фрагментов.
public Struct function parseURLParamString( required String inURLStr ) {
/// Initialize the return struct.
var retStruct = {} ;
// Use listEach() function to iterate over the list with delim "amp;"
arguments.inURLStr.listeach(
function(item){
// listFirst gets 1st list element. listRest() gets all but 1st element. Delim "="
retStruct[listFirst(item,"=")] = listRest(item,"=") ;
}
, "amp;"
) ;
return retStruct ;
}
writeDump( parseURLParamString(string) ) ;
Это вернет:
Затем вы можете просто ссылаться на нужные вам переменные из возвращаемой вами структуры.
Но если вам нужно создать фактические переменные вместо того, чтобы извлекать их из структуры, вы можете сделать это следующим образом:
arguments.inURLStr.listeach(
function(item){
variables[listFirst(item,'=')] = listRest(item,"=") ;
}
, "amp;"
) ;
… а затем измените свою внешнюю функцию либо на return Void
, либо на nothing и удалите из нее структуру. Вы можете ссылаться на переменные, подобные user = #user#
. Для этого потребуется, чтобы вы знали переменные заранее, тогда как при передаче определенной структуры вы можете просто перебирать структуру и выводить ключи / значения. Технически вы также можете перебирать variables
область видимости, но там, вероятно, будет много других переменных.
Если вы хотите, вы также можете использовать getToken()
, но у него те же ограничения, что и у listLast()
. Если ваш value
содержит второй текст-разделитель (например, дополненную строку Base64), то эти символы будут рассматриваться как разделитель и будут исключены из вашего значения. Для base64Msg = QmVFeGNlbGxlbnRUb0VhY2hPdGhlcg==
, getToken()
/ listLast()
вернет QmVFeGNlbGxlbnRUb0VhY2hPdGhlcg
, где listRest()
даст вам QmVFeGNlbGxlbnRUb0VhY2hPdGhlcg==
. Или, что еще хуже, если символ находится в середине строки, он будет усечен. ListLast()
удаляет первый элемент списка с разделителями и возвращает остальную часть списка, поэтому, если ваша строка содержит разделитель, она вернет полное значение.
Наконец, поскольку это, по-видимому, строка из URL, вы, вероятно, захотите очистить и закодировать строку, прежде чем сохранять ее в базе данных.
Если вы сохраните закодированное значение, это, скорее всего, превратит ваши разделители в их закодированные значения. Приведенные выше функции поддерживают только односимвольные разделители, поэтому их нельзя было бы использовать, как указано выше (за исключением декодирования перед отправкой в функцию разделения). listToArray
допускает использование многосимвольных разделителей. Так что это может быть одним из способов разделить их.
В конце концов, существует множество символов, которым разрешена строка URL, #
и =
два из них обязательно вызовут у вас проблемы без кодирования и надлежащей обработки.
Комментарии:
1. Хороший улов! Значения в кодировке Base64. Еще один попался.
Ответ №4:
Вы могли бы использовать «ListToArray», используя «amp;» в качестве разделителя, чтобы разделить каждое значение, а затем использовать снова (или использовать ListFirst и ListLast, если есть только 2 значения), но на этот раз используя «=» в качестве разделителя, таким образом, у вас будет [«user=me@example.com «, «name=John»] в качестве первого результата и [[[пользователь],[me@example.com ]],[[имя],[Джон]]] в качестве второго.
Я обычно рекомендую использовать структуры вместо простых переменных, вот один пример
<cfscript>
/* My Raw string */
MyString = "user=me@example.comamp;name=John";
/* Breaking my single string in multiple values */
MyArrayOfValues = ListToArray(MyString, "amp;");
/* Creating my struct o hold my values */
MyStruct = StructNew();
/* Interating over my values */
for (Value in MyArrayOfValues){
// First Interaction will be: user=me@example.com and the second will be name=John and etc...
/* Get My attribute name */
MyAttributeName = ListFirst(Value, "=");
/* Get My attribute value */
MyAttributeValue = ListLast(Value, "=");
/* Evaluate the values of you borth variables and asign each other */
Evaluate("MyStruct.#LCase(MyAttributeName)# = '#MyAttributeValue#'");
}
/* Here you can see your value printed as struct formed by 2 atributes, name and user, both in lower case */
writeDump(MyStruct);
/* Here one example how to use this data */
writeOutput("
Hi my name is #MyStruct.name# and my user is #MyStruct.user#!
");
</cfscript>
Этот способ является более общим подходом, поскольку вы, вероятно, будете иметь больше столбцов в своей базе данных или даже сможете использовать его с другими данными из другой базы данных, всегда следуя одной и той же структуре… значения, разделенные символом amp; и атрибутом и значением by =
Комментарии:
1. Мой голос просто перевел вашу репутацию в четырехзначные цифры. Ты должен мне пиво.
2. Однако нет необходимости оценивать. Просто используйте структурную нотацию. Кроме того, не забудьте учитывать пустые параметры в функциях списка.
3. Дело в том, что значения из базы данных являются динамическими, поэтому он не сможет узнать, использует ли этот алгоритм в нескольких базах данных… из-за этого я использую Evaluate, я не просто использую что-то вроде (MyStruct. #someValue #) собирается работать, вероятно, вызовет ошибку Sintax