Алгоритм присоединения, например, массив строк

Сервер IP

Вы можете получить IP-адрес сервера с $_SERVER['SERVER_ADDR'].

MAC-адрес сервера

Для MAC-адреса вы можете анализировать вывод netstat -ie в Linux или ipconfig /all в Windows.

Клиентский IP-адрес адрес

Вы можете получить IP-адрес клиента с $_SERVER['REMOTE_ADDR']

MAC-адрес клиента

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];
   }
}

Но что, если клиент не включен LAN?

Ну, вам не повезло, если вы не можете заставить клиента добровольно передавать эту информацию и передавать другим способом.

13
задан knuton 28 May 2011 в 13:40
поделиться

16 ответов

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 ''
 }
0
ответ дан jfs 28 May 2011 в 13:40
поделиться

Perl 6

sub join( $separator, @strings ){
  my $return = shift @strings;
  for @strings -> ( $string ){
    $return ~= $separator ~ $string;
  }
  return $return;
}

Да, я знаю это, бессмыслен, потому что Perl 6 уже имеет функцию соединения.

0
ответ дан Brad Gilbert 28 May 2011 в 13:40
поделиться

join() функция в Ruby:

def join(seq, sep) 
  seq.inject { |total, item| total << sep << item } or "" 
end

join(["a", "b", "c"], ", ")
# => "a, b, c"
0
ответ дан jfs 28 May 2011 в 13:40
поделиться

Самое изящное решение, которое я нашел для проблем как это, является чем-то вроде этого (в псевдокоде)

separator = ""
foreach(item in stringCollection)
{
    concatenatedString += separator + item
    separator = ","
}

, Вы просто выполняете цикл и только после того, как второй раз вокруг разделителя установлен. Так в первый раз это не будет добавлено. Это не столь чисто, как я хотел бы, чтобы он был так, я все еще добавлю комментарии, но это лучше, чем если оператор или добавление первого или последнего объекта вне цикла.

19
ответ дан Mendelt 28 May 2011 в 13:40
поделиться

Следующее больше не является агностиком языка (но это не имеет значения для обсуждения, потому что реализация является легко портативной на другие языки). Я пытался реализовать 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();
}
0
ответ дан Konrad Rudolph 28 May 2011 в 13:40
поделиться

' Псевдо код Предполагает, что нуль базировался

ResultString = InputArray[0]
n = 1
while n (is less than)  Number_Of_Strings
    ResultString (concatenate) ", "
    ResultString (concatenate) InputArray[n]
    n = n + 1
loop
1
ответ дан David L Morris 28 May 2011 в 13:40
поделиться

Строки @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
2
ответ дан jfs 28 May 2011 в 13:40
поделиться

Для чистой элегантности типичное рекурсивное решение функционального языка довольно хорошо. Это не находится в фактическом синтаксисе языка, но Вы получаете идею (это также hardcoded для использования разделителя запятой):

соединение ([]) =""

соединение ([x]) = соединение "x"

([x, отдых]) = "x", + соединение (отдых)

В действительности Вы записали бы это более универсальным способом, для многократного использования того же алгоритма, но краткий обзор далеко тип данных (не должны быть строки), и операция (не должна быть конкатенация с запятой в середине). Тогда это обычно называют, 'уменьшают', и многим функциональным языкам встроили это, например, умножающий все числа в списке, в Lisp:

(уменьшают # '*' (1 2 3 4 5)), => 120

3
ответ дан Luke Halliwell 28 May 2011 в 13:40
поделиться

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

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 ();. путем многократного использования того же строкового разработчика объект мы можем уменьшить объем выделений и мусора, который мы производим.

И прежде чем кто-то согласится с оптимизацией, является злым, мы говорим о реализации общей библиотечной функции. Приемлемая, масштабируемая производительность является одним из требований их. Соединение, которое занимает много времени, является тем, которое это будет не часто используемым.

10
ответ дан Patrick 28 May 2011 в 13:40
поделиться

Я обычно иду с чем-то как...

list = ["Alpha", "Beta", "Gamma"];
output = "";
separator = "";
for (int i = 0; i < list.length ; i++) {
  output = output + separator;
  output = output + list[i];
  separator = ", ";
}

Это работает, потому что на первой передаче, разделитель пуст (таким образом, Вы не получаете запятую в запуске, но на каждой последующей передаче, Вы добавляете запятую прежде, чем добавить следующий элемент.

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

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

3
ответ дан Matt Sheppard 28 May 2011 в 13:40
поделиться

В 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 перед добавлением большего количества байтов к нему.

У Вас или есть к особому случаю первая запись или последнее.

1
ответ дан Community 28 May 2011 в 13:40
поделиться

Большинство языков в наше время - например, жемчуг (упоминание Jon Ericson), php, JavaScript - имеет соединение () функция или метод, и это - безусловно самое изящное решение. Меньше кода является лучшим кодом.

В ответ на Mendelt Siebenga, если бы Вы действительно требуете скрученного вручную решения, я пошел бы с тернарным оператором для чего-то как:

separator = ","
foreach (item in stringCollection)
{
    concatenatedString += concatenatedString ? separator + item : item
}
5
ответ дан Bobby Jack 28 May 2011 в 13:40
поделиться

сбор различных реализаций языка?
Вот, для Вашего развлечения, версии 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 могла бы быть на самом деле контрпродуктивной до реализации - и языковозависимое количество строк.

1
ответ дан blabla999 28 May 2011 в 13:40
поделиться

В 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"));
    }
}
0
ответ дан Mark B 28 May 2011 в 13:40
поделиться

Я записал рекурсивную версию решения в шепелявости. Если длина списка больше, что 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"))

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

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

0
ответ дан 28 May 2011 в 13:40
поделиться

Используйте метод String.join в C#

http://msdn.microsoft.com/en-us/library/57a79xd0.aspx

0
ответ дан 1 December 2019 в 17:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: