Вы можете получить IP-адрес сервера с $_SERVER['SERVER_ADDR']
.
Для MAC-адреса вы можете анализировать вывод netstat -ie
в Linux или ipconfig /all
в Windows.
Вы можете получить IP-адрес клиента с $_SERVER['REMOTE_ADDR']
MAC-адрес клиента не будет доступен вам, за исключением одного особого обстоятельства : , если клиент находится в том же сегменте Ethernet, что и сервер.
Итак, если вы создаете какую-либо систему на базе локальной сети и ваши клиенты , это в том же сегменте Ethernet, тогда вы можете получить MAC-адрес, проанализировав вывод arp -n
(linux) или arp -a
(окна).
Редактирование: вы спрашиваете в комментариях, как получить вывод внешней команды - одним из способов является использование обратных ссылок, например
$ipAddress=$_SERVER['REMOTE_ADDR'];
$macAddr=false;
#run the external command, break output into lines
$arp=`arp -a $ipAddress`;
$lines=explode("\n", $arp);
#look for the output line describing our IP address
foreach($lines as $line)
{
$cols=preg_split('/\s+/', trim($line));
if ($cols[0]==$ipAddress)
{
$macAddr=$cols[1];
}
}
Ну, вам не повезло, если вы не можете заставить клиента добровольно передавать эту информацию и передавать другим способом.
join()
в Perl:
use List::Util qw(reduce);
sub mjoin($@) {$sep = shift; reduce {$a.$sep.$b} @_ or ''}
say mjoin(', ', qw(Alpha Beta Gamma));
# Alpha, Beta, Gamma
Или без reduce
:
sub mjoin($@)
{
my ($sep, $sum) = (shift, shift);
$sum .= $sep.$_ for (@_);
$sum or ''
}
sub join( $separator, @strings ){
my $return = shift @strings;
for @strings -> ( $string ){
$return ~= $separator ~ $string;
}
return $return;
}
Да, я знаю это, бессмыслен, потому что Perl 6 уже имеет функцию соединения.
join()
функция в Ruby:
def join(seq, sep)
seq.inject { |total, item| total << sep << item } or ""
end
join(["a", "b", "c"], ", ")
# => "a, b, c"
Самое изящное решение, которое я нашел для проблем как это, является чем-то вроде этого (в псевдокоде)
separator = ""
foreach(item in stringCollection)
{
concatenatedString += separator + item
separator = ","
}
, Вы просто выполняете цикл и только после того, как второй раз вокруг разделителя установлен. Так в первый раз это не будет добавлено. Это не столь чисто, как я хотел бы, чтобы он был так, я все еще добавлю комментарии, но это лучше, чем если оператор или добавление первого или последнего объекта вне цикла.
Следующее больше не является агностиком языка (но это не имеет значения для обсуждения, потому что реализация является легко портативной на другие языки). Я пытался реализовать Luke (theretically лучше всего) решение на императивном языке программирования. Выберите; C# шахты. Не очень изящный вообще. Однако (без любого тестирования вообще) я мог предположить, что его производительность довольно достойна, потому что рекурсия является на самом деле рекурсивным хвостом.
Мой вызов: дайте лучшую рекурсивную реализацию (на императивном языке). Вы говорите, что означает “better”: меньше кода, быстрее, я открыт для предложений.
private static StringBuilder RecJoin(IEnumerator<string> xs, string sep, StringBuilder result) {
result.Append(xs.Current);
if (xs.MoveNext()) {
result.Append(sep);
return RecJoin(xs, sep, result);
} else
return result;
}
public static string Join(this IEnumerable<string> xs, string separator) {
var i = xs.GetEnumerator();
if (!i.MoveNext())
return string.Empty;
else
return RecJoin(i, separator, new StringBuilder()).ToString();
}
' Псевдо код Предполагает, что нуль базировался
ResultString = InputArray[0] n = 1 while n (is less than) Number_Of_Strings ResultString (concatenate) ", " ResultString (concatenate) InputArray[n] n = n + 1 loop
Строки @Mendelt Siebenga
являются ключевыми объектами на языках программирования. Различные языки реализуют строки по-другому. Реализация join()
сильно зависит от конкретной реализации строк. Псевдокод не отражает конкретную реализацию.
Рассматривают join()
в Python. Это может легко использоваться:
print ", ".join(["Alpha", "Beta", "Gamma"])
# Alpha, Beta, Gamma
Это могло быть легко реализовано следующим образом:
def join(seq, sep=" "):
if not seq: return ""
elif len(seq) == 1: return seq[0]
return reduce(lambda x, y: x + sep + y, seq)
print join(["Alpha", "Beta", "Gamma"], ", ")
# Alpha, Beta, Gamma
И здесь как join()
метод реализован в C (взятый от соединительная линия ):
PyDoc_STRVAR(join__doc__,
"S.join(sequence) -> string\n\
\n\
Return a string which is the concatenation of the strings in the\n\
sequence. The separator between elements is S.");
static PyObject *
string_join(PyStringObject *self, PyObject *orig)
{
char *sep = PyString_AS_STRING(self);
const Py_ssize_t seplen = PyString_GET_SIZE(self);
PyObject *res = NULL;
char *p;
Py_ssize_t seqlen = 0;
size_t sz = 0;
Py_ssize_t i;
PyObject *seq, *item;
seq = PySequence_Fast(orig, "");
if (seq == NULL) {
return NULL;
}
seqlen = PySequence_Size(seq);
if (seqlen == 0) {
Py_DECREF(seq);
return PyString_FromString("");
}
if (seqlen == 1) {
item = PySequence_Fast_GET_ITEM(seq, 0);
if (PyString_CheckExact(item) || PyUnicode_CheckExact(item)) {
Py_INCREF(item);
Py_DECREF(seq);
return item;
}
}
/* There are at least two things to join, or else we have a subclass
* of the builtin types in the sequence.
* Do a pre-pass to figure out the total amount of space we'll
* need (sz), see whether any argument is absurd, and defer to
* the Unicode join if appropriate.
*/
for (i = 0; i < seqlen; i++) {
const size_t old_sz = sz;
item = PySequence_Fast_GET_ITEM(seq, i);
if (!PyString_Check(item)){
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(item)) {
/* Defer to Unicode join.
* CAUTION: There's no gurantee that the
* original sequence can be iterated over
* again, so we must pass seq here.
*/
PyObject *result;
result = PyUnicode_Join((PyObject *)self, seq);
Py_DECREF(seq);
return result;
}
#endif
PyErr_Format(PyExc_TypeError,
"sequence item %zd: expected string,"
" %.80s found",
i, Py_TYPE(item)->tp_name);
Py_DECREF(seq);
return NULL;
}
sz += PyString_GET_SIZE(item);
if (i != 0)
sz += seplen;
if (sz < old_sz || sz > PY_SSIZE_T_MAX) {
PyErr_SetString(PyExc_OverflowError,
"join() result is too long for a Python string");
Py_DECREF(seq);
return NULL;
}
}
/* Allocate result space. */
res = PyString_FromStringAndSize((char*)NULL, sz);
if (res == NULL) {
Py_DECREF(seq);
return NULL;
}
/* Catenate everything. */
p = PyString_AS_STRING(res);
for (i = 0; i < seqlen; ++i) {
size_t n;
item = PySequence_Fast_GET_ITEM(seq, i);
n = PyString_GET_SIZE(item);
Py_MEMCPY(p, PyString_AS_STRING(item), n);
p += n;
if (i < seqlen - 1) {
Py_MEMCPY(p, sep, seplen);
p += seplen;
}
}
Py_DECREF(seq);
return res;
}
<час> Примечание, что вышеупомянутой Catenate everything.
код является небольшая часть целой функции.
В псевдокоде:
/* Catenate everything. */
for each item in sequence
copy-assign item
if not last item
copy-assign separator
Для чистой элегантности типичное рекурсивное решение функционального языка довольно хорошо. Это не находится в фактическом синтаксисе языка, но Вы получаете идею (это также hardcoded для использования разделителя запятой):
соединение ([]) =""
соединение ([x]) = соединение "x"
([x, отдых]) = "x", + соединение (отдых)
В действительности Вы записали бы это более универсальным способом, для многократного использования того же алгоритма, но краткий обзор далеко тип данных (не должны быть строки), и операция (не должна быть конкатенация с запятой в середине). Тогда это обычно называют, 'уменьшают', и многим функциональным языкам встроили это, например, умножающий все числа в списке, в Lisp:
(уменьшают # '*' (1 2 3 4 5)), => 120
Всеми этими решениями являются достойные, но для базовой библиотеки, и независимость разделителя и достойная скорость важны. Вот функция, которая соответствует требованию, предполагающему, что язык имеет некоторую форму строкового разработчика.
public static string join(String[] strings, String sep) {
if(strings.length == 0) return "";
if(strings.length == 1) return strings[0];
StringBuilder sb = new StringBuilder();
sb.append(strings[0]);
for(int i = 1; i < strings.length; i++) {
sb.append(sep);
sb.append(strings[i]);
}
return sb.toString();
}
РЕДАКТИРОВАНИЕ: Я предполагаю, что должен упомянуть, почему это было бы более быстро. Главная причина состояла бы в том, потому что любое время Вы называете c = + b; базовая конструкция обычно c = (новый StringBuilder ()) .append (a) .append (b) .toString ();. путем многократного использования того же строкового разработчика объект мы можем уменьшить объем выделений и мусора, который мы производим.
И прежде чем кто-то согласится с оптимизацией, является злым, мы говорим о реализации общей библиотечной функции. Приемлемая, масштабируемая производительность является одним из требований их. Соединение, которое занимает много времени, является тем, которое это будет не часто используемым.
Я обычно иду с чем-то как...
list = ["Alpha", "Beta", "Gamma"];
output = "";
separator = "";
for (int i = 0; i < list.length ; i++) {
output = output + separator;
output = output + list[i];
separator = ", ";
}
Это работает, потому что на первой передаче, разделитель пуст (таким образом, Вы не получаете запятую в запуске, но на каждой последующей передаче, Вы добавляете запятую прежде, чем добавить следующий элемент.
Вы могли, конечно, развернуть это немного для создания его немного быстрее (присваивающий разделителю, много раз не идеально), хотя я подозреваю, что это - что-то, что компилятор мог сделать для Вас автоматически.
В конце, хотя, я подозреваю симпатичный, это что большинство функций соединения уровня языка, к которым сводятся. Не что иное как сахар синтаксиса, но это уверенный сладко.
В Perl я просто использую команду соединения:
$ echo "Alpha
Beta
Gamma" | perl -e 'print(join(", ", map {chomp; $_} <> ))'
Alpha, Beta, Gamma
(Материал карты должен главным образом там создать список.)
На языках, которые не имеют встроенного, как C, я использую простое (непротестированное) повторение:
for (i = 0; i < N-1; i++){
strcat(s, a[i]);
strcat(s, ", ");
}
strcat(s, a[N]);
Конечно, необходимо было бы проверить размер s перед добавлением большего количества байтов к нему.
У Вас или есть к особому случаю первая запись или последнее.
Большинство языков в наше время - например, жемчуг (упоминание Jon Ericson), php, JavaScript - имеет соединение () функция или метод, и это - безусловно самое изящное решение. Меньше кода является лучшим кодом.
В ответ на Mendelt Siebenga, если бы Вы действительно требуете скрученного вручную решения, я пошел бы с тернарным оператором для чего-то как:
separator = ","
foreach (item in stringCollection)
{
concatenatedString += concatenatedString ? separator + item : item
}
сбор различных реализаций языка?
Вот, для Вашего развлечения, версии Smalltalk:
join:collectionOfStrings separatedBy:sep
|buffer|
buffer := WriteStream on:''.
collectionOfStrings
do:[:each | buffer nextPutAll:each ]
separatedBy:[ buffer nextPutAll:sep ].
^ buffer contents.
, Конечно, вышеупомянутый код уже находится в стандартной библиотеке, найденной как:
Набор>> asStringWith:
так, с помощью этого, Вы записали бы:
#('A' 'B' 'C') asStringWith:','
, Но вот мой основной момент :
я хотел бы поставить больше акцента на том, что использование StringBuilder (или что называют "WriteStream" в Smalltalk) настоятельно рекомендовано. Не связывайте строковое использование "+" в цикле - результат будет многими много промежуточных холостых строк. Если у Вас есть хороший Сборщик "мусора", это прекрасно. Но некоторые не, и большая память должна быть исправлена. StringBuilder (и WriteStream, который является его главным дедушкой) используют удвоение буфера или даже адаптивный растущий алгоритм, для которого нужно ОЧЕНЬ меньше памяти царапины.
Однако, если его единственное несколько маленьких строк Вы конкатенируете, не заботьтесь, и "+" их; дополнительная работа с помощью StringBuilder могла бы быть на самом деле контрпродуктивной до реализации - и языковозависимое количество строк.
В Java 5, с модульным тестом:
import junit.framework.Assert;
import org.junit.Test;
public class StringUtil
{
public static String join(String delim, String... strings)
{
StringBuilder builder = new StringBuilder();
if (strings != null)
{
for (String str : strings)
{
if (builder.length() > 0)
{
builder.append(delim);
}
builder.append(str);
}
}
return builder.toString();
}
@Test
public void joinTest()
{
Assert.assertEquals("", StringUtil.join(", ", null));
Assert.assertEquals("", StringUtil.join(", ", ""));
Assert.assertEquals("", StringUtil.join(", ", new String[0]));
Assert.assertEquals("test", StringUtil.join(", ", "test"));
Assert.assertEquals("foo, bar", StringUtil.join(", ", "foo", "bar"));
Assert.assertEquals("foo, bar, baz", StringUtil.join(", ", "foo", "bar", "baz"));
}
}
Я записал рекурсивную версию решения в шепелявости. Если длина списка больше, что 2 это разделяет список во вдвое менее лучшем, чем это может и затем пытаться объединить подсписки
(defun concatenate-string(list)
(cond ((= (length list) 1) (car list))
((= (length list) 2) (concatenate 'string (first list) "," (second list)))
(t (let ((mid-point (floor (/ (- (length list) 1) 2))))
(concatenate 'string
(concatenate-string (subseq list 0 mid-point))
","
(concatenate-string (subseq list mid-point (length list))))))))
(concatenate-string '("a" "b"))
, я пытался применить деление, и завоюйте стратегию к проблеме, но я предполагаю, что это не дает лучший результат, чем простое повторение. Сообщите мне возможно, ли это, было добито большего успеха.
я также выполнил анализ рекурсии, полученной алгоритмом, это доступно здесь .