问:
Doubly circular linked list strange behaviour
I use the following code snippet to add an element to the back of my doubly circular linked list.

```<code>typedef struct node
{
    int nb;
    struct node *prev;
    struct node *next;
} st_node;

void add_back(st_node *origin, st_node *node)
{
    st_node *tmp;

    if (!origin || !node)
        exit(1);
    tmp = origin;
    while (tmp->next != origin)
        tmp = tmp->next;
    tmp->next = node;
    node->prev = tmp;
    node->next = origin;
    origin->prev = node;
}
</code>```

Then I print my list with the folling function :

```<code>void    printer(st_node *origin)
{
    st_node *node;

    node = origin;
    while (node->next != origin)
    {
        printf("%d\n", node->nb);
        node = node->next;
    }
    printf("%d\n", node->nb);
}
</code>```

I got the origin value with printf and then random values in a loop. I don't know what to do and I realized origin->prev = node; was causing the problem inside the add_back function but I don't know why.

Here's the main:

```<code>int main(int ac, char **av)
{
    st_node     *stack;
    int         i;

    if (ac <= 2)
        return (1);
    stack = create_element(atoi(av[1]));
    i = 2;
    while (i < ac)
        add_back(stack, create_element(atoi(av[i++])));
    printf("Stack:\n");
    printer(stack);
}
</code>```
```<code>st_node *create_element(int nb)
{
    st_node *element;
    element = malloc(sizeof(st_node *));
    element->nb = nb;
    element->next = element;
    element->prev = element;
    return (element);
}

</code>```

答:
Several bugs:

malloc in create_element is wrong

In add_back, the order of the link setting is wrong

In add_back, no need to loop to find the tail node. It is origin->prev

The printer function will segfault on an empty list because it is dereferencing node before checking whether it is non-null

The first if in main is too strict: It does not allow: ./myprogram 1 (i.e. a list with one element)

Here is the refactored/working code. It is annotated with the bugs/fixes:

```<code>#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int nb;
    struct node *prev;
    struct node *next;
} st_node;

st_node *
create_element(int nb)
{
    st_node *element;

// NOTE/BUG: does _not_ allocate enough space (causing UB/undefined behavior)
#if 0
    element = malloc(sizeof(st_node *));
#else
    element = malloc(sizeof(*element));
#endif
    element->nb = nb;
    element->next = element;
    element->prev = element;
    return (element);
}

void
add_back(st_node *origin, st_node *node)
{
    st_node *tmp;

    if (!origin || !node)
        exit(1);

// NOTE/BUG: no need to traverse -- origin->prev is the back
#if 0
    tmp = origin;
    while (tmp->next != origin)
        tmp = tmp->next;
#else
    tmp = origin->prev;
#endif

// NOTE/BUG: order and set is incorrect -- causes self loop
#if 0
    tmp->next = node;
    node->prev = tmp;
    node->next = origin;
#else
    node->prev = tmp;
    node->next = tmp->next;
    tmp->next = node;
#endif
    origin->prev = node;
}

void
printer(st_node *origin)
{
    st_node *node;

// NOTE/BUG: this will segfault on an empty list
#if 1
    node = origin;
    while (node->next != origin) {
        printf("%d\n", node->nb);
        node = node->next;
    }
    printf("%d\n", node->nb);
#else
    node = origin;
    if (node != NULL) {
        while (1) {
            printf("%d\n", node->nb);
            node = node->next;
            if (node == origin)
                break;
        }
    }
#endif
}

int
main(int ac, char **av)
{
    st_node *stack;
    int i;

// NOTE/BUG: does _not_ allow for list of only one element
#if 0
    if (ac <= 2) {
#else
    if (ac < 2) {
#endif
        printf("main: too short\n");
        return (1);
    }
    stack = create_element(atoi(av[1]));

// NOTE/BUG: for loop is cleaner
#if 0
    i = 2;
    while (i < ac)
        add_back(stack, create_element(atoi(av[i++])));
#else
    for (i = 2;  i < ac;  ++i)
        add_back(stack, create_element(atoi(av[i])));
#endif

    printf("Stack:\n");
    printer(stack);
}
</code>```

In the above, I used cpp conditionals to denote old/broken vs. new/fixed code:

```<code>#if 0
// old code
#else
// new code
#endif
</code>```

The above code fixed most of the bugs, but the program could not create an empty list.

Here's some more cleanup/refactoring to make the program more general. In particular, I generalized add_back to allow adding a node to an empty list. In the original code, it treated this as a fatal exit condition.

```<code>#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int nb;
    struct node *prev;
    struct node *next;
} st_node;

st_node *
create_element(int nb)
{
    st_node *element;

    element = malloc(sizeof(*element));
    element->nb = nb;
    element->next = element;
    element->prev = element;
    return (element);
}

st_node *
add_back(st_node *origin, st_node *node)
{
    st_node *tmp;

    if (node == NULL)
        exit(1);

    do {
        // add to empty list
        if (origin == NULL) {
            origin = node;
            break;
        }

        tmp = origin->prev;

        node->prev = tmp;
        node->next = tmp->next;
        tmp->next = node;
        origin->prev = node;
    } while (0);

    return origin;
}

void
printer(st_node *origin)
{
    st_node *node;

    node = origin;
    if (node != NULL) {
        while (1) {
            printf("%d\n", node->nb);
            node = node->next;
            if (node == origin)
                break;
        }
    }
}

int
main(int ac, char **av)
{
    st_node *stack = NULL;
    int i;

    for (i = 1;  i < ac;  ++i)
        stack = add_back(stack, create_element(atoi(av[i])));

    printf("Stack:\n");
    printer(stack);
}
</code>```

Body:
I use the following code snippet to add an element to the back of my doubly circular linked list.

typedef struct node
{
    int nb;
    struct node *prev;
    struct node *next;
} st_node;

void add_back(st_node *origin, st_node *node)
{
    st_node *tmp;

    if (!origin || !node)
        exit(1);
    tmp = origin;
    while (tmp->next != origin)
        tmp = tmp->next;
    tmp->next = node;
    node->prev = tmp;
    node->next = origin;
    origin->prev = node;
}

Then I print my list with the folling function :

void    printer(st_node *origin)
{
    st_node *node;

    node = origin;
    while (node->next != origin)
    {
        printf("%d\n", node->nb);
        node = node->next;
    }
    printf("%d\n", node->nb);
}

I got the origin value with printf and then random values in a loop. I don't know what to do and I realized origin->prev = node; was causing the problem inside the add_back function but I don't know why.

Here's the main:

int main(int ac, char **av)
{
    st_node     *stack;
    int         i;

    if (ac <= 2)
        return (1);
    stack = create_element(atoi(av[1]));
    i = 2;
    while (i < ac)
        add_back(stack, create_element(atoi(av[i++])));
    printf("Stack:\n");
    printer(stack);
}

st_node *create_element(int nb)
{
    st_node *element;
    element = malloc(sizeof(st_node *));
    element->nb = nb;
    element->next = element;
    element->prev = element;
    return (element);
}

Body:
Several bugs:

malloc in create_element is wrong

In add_back, the order of the link setting is wrong

In add_back, no need to loop to find the tail node. It is origin->prev

The printer function will segfault on an empty list because it is dereferencing node before checking whether it is non-null

The first if in main is too strict: It does not allow: ./myprogram 1 (i.e. a list with one element)

Here is the refactored/working code. It is annotated with the bugs/fixes:

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int nb;
    struct node *prev;
    struct node *next;
} st_node;

st_node *
create_element(int nb)
{
    st_node *element;

// NOTE/BUG: does _not_ allocate enough space (causing UB/undefined behavior)
#if 0
    element = malloc(sizeof(st_node *));
#else
    element = malloc(sizeof(*element));
#endif
    element->nb = nb;
    element->next = element;
    element->prev = element;
    return (element);
}

void
add_back(st_node *origin, st_node *node)
{
    st_node *tmp;

    if (!origin || !node)
        exit(1);

// NOTE/BUG: no need to traverse -- origin->prev is the back
#if 0
    tmp = origin;
    while (tmp->next != origin)
        tmp = tmp->next;
#else
    tmp = origin->prev;
#endif

// NOTE/BUG: order and set is incorrect -- causes self loop
#if 0
    tmp->next = node;
    node->prev = tmp;
    node->next = origin;
#else
    node->prev = tmp;
    node->next = tmp->next;
    tmp->next = node;
#endif
    origin->prev = node;
}

void
printer(st_node *origin)
{
    st_node *node;

// NOTE/BUG: this will segfault on an empty list
#if 1
    node = origin;
    while (node->next != origin) {
        printf("%d\n", node->nb);
        node = node->next;
    }
    printf("%d\n", node->nb);
#else
    node = origin;
    if (node != NULL) {
        while (1) {
            printf("%d\n", node->nb);
            node = node->next;
            if (node == origin)
                break;
        }
    }
#endif
}

int
main(int ac, char **av)
{
    st_node *stack;
    int i;

// NOTE/BUG: does _not_ allow for list of only one element
#if 0
    if (ac <= 2) {
#else
    if (ac < 2) {
#endif
        printf("main: too short\n");
        return (1);
    }
    stack = create_element(atoi(av[1]));

// NOTE/BUG: for loop is cleaner
#if 0
    i = 2;
    while (i < ac)
        add_back(stack, create_element(atoi(av[i++])));
#else
    for (i = 2;  i < ac;  ++i)
        add_back(stack, create_element(atoi(av[i])));
#endif

    printf("Stack:\n");
    printer(stack);
}

In the above, I used cpp conditionals to denote old/broken vs. new/fixed code:

#if 0
// old code
#else
// new code
#endif

The above code fixed most of the bugs, but the program could not create an empty list.

Here's some more cleanup/refactoring to make the program more general. In particular, I generalized add_back to allow adding a node to an empty list. In the original code, it treated this as a fatal exit condition.

#include <stdio.h>
#include <stdlib.h>

typedef struct node {
    int nb;
    struct node *prev;
    struct node *next;
} st_node;

st_node *
create_element(int nb)
{
    st_node *element;

    element = malloc(sizeof(*element));
    element->nb = nb;
    element->next = element;
    element->prev = element;
    return (element);
}

st_node *
add_back(st_node *origin, st_node *node)
{
    st_node *tmp;

    if (node == NULL)
        exit(1);

    do {
        // add to empty list
        if (origin == NULL) {
            origin = node;
            break;
        }

        tmp = origin->prev;

        node->prev = tmp;
        node->next = tmp->next;
        tmp->next = node;
        origin->prev = node;
    } while (0);

    return origin;
}

void
printer(st_node *origin)
{
    st_node *node;

    node = origin;
    if (node != NULL) {
        while (1) {
            printf("%d\n", node->nb);
            node = node->next;
            if (node == origin)
                break;
        }
    }
}

int
main(int ac, char **av)
{
    st_node *stack = NULL;
    int i;

    for (i = 1;  i < ac;  ++i)
        stack = add_back(stack, create_element(atoi(av[i])));

    printf("Stack:\n");
    printer(stack);
}


来源: stackexchange

问:
Cannot pickle object: maximum recursion depth exceeded
I'm trying to pickle objects that I generate in a script to process them afterwards, but I get this error:

```<code>File "<ipython-input-2-0f716e86ecd3>", line 1, in <module>
pickle.dump(thisperson, output, pickle.HIGHEST_PROTOCOL)
RecursionError: maximum recursion depth exceeded while pickling an object
</code>```

Here thisperson is relatively simple (or so I thought): a name and a dictionary containing attributes:

```<code>class Attributes:
    def __init__(self, what_attr, attr):
        self._what_attr = what_attr
        self._attributes = attr

    @property
    def what_attr(self):
        return self._what_attr
    @what_attr.setter
    def what_attr(self, new_value):
        self._what_attr = new_value

    @property
    def attributes(self):
        return self._attributes
    @attributes.setter
    def attributes(self, new_value):
        self._attributes = new_value

class Person:
    def __init__(self, watname, watage):
        self._myname = watname
        self._age = watage
        self._attributes = []

    @property
    def attributes(self):
        return self._attributes
    @attributes.setter
    def attributes(self, attributes_list):
        self._attributes = attributes_list

    @property
    def myname(self):
        return self._myname
    @myname.setter
    def myname(self, value):
        self._myname = value

    @property
    def age(self):
        return self._age
    @age.setter
    def age(self, value):
        self._age = value
</code>```

the pickle function looks like this:

import pickle

```<code>def save_person(person, mypath):
    import os
    if not os.path.exists(mypath):
        os.makedirs(mypath)
    my_path = mypath + str(person.myname)
    if not os.path.exists(my_path + '/'):
        os.makedirs(my_path + '/')
    with open(my_path + '.pkl', 'wb') as output:
        pickle.dump(person, output, pickle.HIGHEST_PROTOCOL)
</code>```

This error seems to be coming from the fact that the class contains a string and a dict because if I keep attributes as an empty dict I don't get the error.

Is there another way I can pickle objects like these?

I tried increasing sys.setrecursionlimit, but that didn't help.

Edit:
.... i can't reproduce the error if i use a short version of the code .... go figure.
@MinhNguyen something weird is that i create my attributes dict in a function (attr = get_attributes(data)), but when i create the same dict myself, i can pickle it ....

```<code>thisperson = Person("Kenny", 22, {})
attr = get_attributes(data)  # returns {'eyes': 'blue', 'hair': 'brown'}
this_attr = Attributes(person_name, attr)
this_person.attributes.append(this_attr)
save_person(this_person, main_folder)

Exception ignored in:
'_pydevd_frame_eval.pydevd_frame_evaluator_win32_37_64.get_bytecode_while_frame_eval'
 RecursionError: maximum recursion depth exceeded while calling a Python object
 Process finished with exit code -1073741819 (0xC0000005)
</code>```

but if i do the following it works:

```<code> attr = {'eyes': 'blue', 'hair': 'brown'}
 this_attr = Attributes(person_name, attr)
 this_person.attributes.append(this_attr)
 save_person(this_person, main_folder)
</code>```

Solution

Alright so after further digging, i found here that pickle doesnt mingle with dict well and will often crash.

So the workaround was that i dropped the Attribute class completely and now my Person's _attribute is a string of dict self._attributes = str(dict()) and whenever i want to add things to it, i'll do an eval(), update() and str() again.

This seem to be working so far...

答:
Problem

I've been using the concurrent.futures module, particularly the ProcessPoolExecutor class, which uses (kind of under the hood) pickle module to return values to the main process.
The issue with this, is that pickle module seems to have a limit on what you can "pickle-ize" when we are talking about nested stuff. In my case, I had a structure like the following:

```<code>data = [
    {
        "string_list": [
            ["a1", "a2", ..., "an"],
            ["b1", "b2", ..., "bn"],
            ...
            ["n1", "n2", ..., "nn"],
        ]
    },
    {
        "string_list": [
            ["a1", "a2", ..., "an"],
            ["b1", "b2", ..., "bn"],
            ...
            ["n1", "n2", ..., "nn"],
        ]
    },

</code>```

Basically, it was a list of dictionaries, which everyone of them contained, a list of string lists. I mean, it was a relatively nested structure. And every time i tried to get the data from the ProcessPoolExecutor's result, it raised a RecursionError: maximum recursion depth exceeded while pickling an object, due to pickle module, which can't (apparently) deal with this level of nesting.

Solution

My solution was similar to the provided in the edited question. I "stringified" the structure before pickling it, and then undone it once I could access the data. Personally, I used json module, which also comes with Python Standard Library.

This was my "experience" dealing with the pickle module.

ContentLicense: CC BY-SA 4.0

Body:
I'm trying to pickle objects that I generate in a script to process them afterwards, but I get this error:

File "<ipython-input-2-0f716e86ecd3>", line 1, in <module>
pickle.dump(thisperson, output, pickle.HIGHEST_PROTOCOL)
RecursionError: maximum recursion depth exceeded while pickling an object

Here thisperson is relatively simple (or so I thought): a name and a dictionary containing attributes:

class Attributes:
    def __init__(self, what_attr, attr):
        self._what_attr = what_attr
        self._attributes = attr

    @property
    def what_attr(self):
        return self._what_attr
    @what_attr.setter
    def what_attr(self, new_value):
        self._what_attr = new_value

    @property
    def attributes(self):
        return self._attributes
    @attributes.setter
    def attributes(self, new_value):
        self._attributes = new_value

class Person:
    def __init__(self, watname, watage):
        self._myname = watname
        self._age = watage
        self._attributes = []

    @property
    def attributes(self):
        return self._attributes
    @attributes.setter
    def attributes(self, attributes_list):
        self._attributes = attributes_list

    @property
    def myname(self):
        return self._myname
    @myname.setter
    def myname(self, value):
        self._myname = value

    @property
    def age(self):
        return self._age
    @age.setter
    def age(self, value):
        self._age = value

the pickle function looks like this:

import pickle

def save_person(person, mypath):
    import os
    if not os.path.exists(mypath):
        os.makedirs(mypath)
    my_path = mypath + str(person.myname)
    if not os.path.exists(my_path + '/'):
        os.makedirs(my_path + '/')
    with open(my_path + '.pkl', 'wb') as output:
        pickle.dump(person, output, pickle.HIGHEST_PROTOCOL)

This error seems to be coming from the fact that the class contains a string and a dict because if I keep attributes as an empty dict I don't get the error.

Is there another way I can pickle objects like these?

I tried increasing sys.setrecursionlimit, but that didn't help.

Edit:
.... i can't reproduce the error if i use a short version of the code .... go figure.
@MinhNguyen something weird is that i create my attributes dict in a function (attr = get_attributes(data)), but when i create the same dict myself, i can pickle it ....

thisperson = Person("Kenny", 22, {})
attr = get_attributes(data)  # returns {'eyes': 'blue', 'hair': 'brown'}
this_attr = Attributes(person_name, attr)
this_person.attributes.append(this_attr)
save_person(this_person, main_folder)

Exception ignored in:
'_pydevd_frame_eval.pydevd_frame_evaluator_win32_37_64.get_bytecode_while_frame_eval'
 RecursionError: maximum recursion depth exceeded while calling a Python object
 Process finished with exit code -1073741819 (0xC0000005)

but if i do the following it works:

 attr = {'eyes': 'blue', 'hair': 'brown'}
 this_attr = Attributes(person_name, attr)
 this_person.attributes.append(this_attr)
 save_person(this_person, main_folder)

Solution

Alright so after further digging, i found here that pickle doesnt mingle with dict well and will often crash.

So the workaround was that i dropped the Attribute class completely and now my Person's _attribute is a string of dict self._attributes = str(dict()) and whenever i want to add things to it, i'll do an eval(), update() and str() again.

This seem to be working so far...

Body:
Problem

I've been using the concurrent.futures module, particularly the ProcessPoolExecutor class, which uses (kind of under the hood) pickle module to return values to the main process.
The issue with this, is that pickle module seems to have a limit on what you can "pickle-ize" when we are talking about nested stuff. In my case, I had a structure like the following:

data = [
    {
        "string_list": [
            ["a1", "a2", ..., "an"],
            ["b1", "b2", ..., "bn"],
            ...
            ["n1", "n2", ..., "nn"],
        ]
    },
    {
        "string_list": [
            ["a1", "a2", ..., "an"],
            ["b1", "b2", ..., "bn"],
            ...
            ["n1", "n2", ..., "nn"],
        ]
    },

Basically, it was a list of dictionaries, which everyone of them contained, a list of string lists. I mean, it was a relatively nested structure. And every time i tried to get the data from the ProcessPoolExecutor's result, it raised a RecursionError: maximum recursion depth exceeded while pickling an object, due to pickle module, which can't (apparently) deal with this level of nesting.

Solution

My solution was similar to the provided in the edited question. I "stringified" the structure before pickling it, and then undone it once I could access the data. Personally, I used json module, which also comes with Python Standard Library.

This was my "experience" dealing with the pickle module.


问:
Simple Form not showing errors at top
I have a simple_form form setup and it will show inline errors fine. I have had problems with some users not seeing these errors and have had requests for a clear enumeration at the top of the very long form. I've used the code setup from the Rails Tutorial:

```<code> <% if object.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-error">
      The form contains <%= pluralize(object.errors.count, "error") %>.
    </div>
    <ul>
      <% object.errors.full_messages.each do |msg| %>
        <li><%= msg %></li>
      <% end %>
    </ul>
  </div>
<% end %>
</code>```

Which is called as a partial (loaded from app/views/application) onto the form (object = f.object). It does not render, but I'll see the failure in the rails console in development. Any ideas why this won't show errors in this fashion? Is this some failure related to Turbo/Hotwire (there is a controller watching the text area to resize if content overflows)?

A much shorter form that also uses the same error partial (and exhibits the same behavior):

```<code><%= simple_form_for [:admin, @annotation] do |f| %>
  <%= render 'error_messages', object: f.object %>

  <%= f.input :abbreviation,
              input_html: { minlength: 1 } %>
  <%= f.input :name,
              input_html: { minlength: 1 } %>
  <%= f.input :description,
              as: :text,
              input_html: { data: { controller: "textarea-autogrow"} },
              input_html: { minlength: 1 } %>
  <fieldset>
    <legend>Used For</legend>
    <%= f.input :oa,
                as: :boolean,
                label: "OA (Lodge, Chapter, Section) Issues" %>
    <%= f.input :council,
                as: :boolean,
                label: "Council (CSP, JSP, etc) Issues" %>
    <%= f.input :camp,
                as: :boolean,
                label: "Camp Issues" %>
  </fieldset>

  <%= f.button :submit,
               data: { disable_with: "Please wait..." }  %>
<% end %>
</code>```

答:
With some help from Michael Koper, we were able to sort this out. The controller methods were missing status: :unprocessable_entity on the format.html statements. So changing:

format.html { render action: "new"}

to

format.html { render action: "new", status: :unprocessable_entity }

Solved this issue.

Title: Simple Form not showing errors at top

Body:
I have a simple_form form setup and it will show inline errors fine. I have had problems with some users not seeing these errors and have had requests for a clear enumeration at the top of the very long form. I've used the code setup from the Rails Tutorial:

 <% if object.errors.any? %>

      The form contains <%= pluralize(object.errors.count, "error") %>.

      <% object.errors.full_messages.each do |msg| %>

<%= msg %>

      <% end %>

<% end %>

Which is called as a partial (loaded from app/views/application) onto the form (object = f.object). It does not render, but I'll see the failure in the rails console in development. Any ideas why this won't show errors in this fashion? Is this some failure related to Turbo/Hotwire (there is a controller watching the text area to resize if content overflows)?

A much shorter form that also uses the same error partial (and exhibits the same behavior):

<%= simple_form_for [:admin, @annotation] do |f| %>
  <%= render 'error_messages', object: f.object %>

  <%= f.input :abbreviation,
              input_html: { minlength: 1 } %>
  <%= f.input :name,
              input_html: { minlength: 1 } %>
  <%= f.input :description,
              as: :text,
              input_html: { data: { controller: "textarea-autogrow"} },
              input_html: { minlength: 1 } %>
  <fieldset>
    <legend>Used For</legend>
    <%= f.input :oa,
                as: :boolean,
                label: "OA (Lodge, Chapter, Section) Issues" %>
    <%= f.input :council,
                as: :boolean,
                label: "Council (CSP, JSP, etc) Issues" %>
    <%= f.input :camp,
                as: :boolean,
                label: "Camp Issues" %>
  </fieldset>

  <%= f.button :submit,
               data: { disable_with: "Please wait..." }  %>
<% end %>


问:
Add leading zeros to integer section of filename
I have folders of images with names like HolidaySnapsJune-1.tif , HolidaySnapsMay-12.tif and HolidaySnaps2018-005.tif

I want to add one leading 0 to the integer section of the filename if it is 2 digits long, and I want to add two leading 00s if it is just one digit long.

I have tried variations of

```<code>find . -name '*\_[0-9][0-9].tif' -exec sh -c '
for fpath do
  echo mv "$fpath" "${fpath%/*}/${fpath##*/}"
done' _ {} +
</code>```

But these put the leading zeros in front of the full file name instead of in front of the integer section.

I would love to do this is a bash script which would recursively work on folders so it's important that the difference in names preceeding the '-' is ignored or worked-around.

I'm on Windows and just have access to whatever is built into git-bashso bash, sed, awk etc.

答:
So, after looking through the answers submitted here and elsewhere on SO this is what I ame up with:

```<code>find . -name '*\-[0-9][0-9].tif' -exec sh -c '
for f do
  mv "$f" "${f//\-/\-0}";
  echo "$f"
done' _ {} +
</code>```

This works on files with two digits in the integer section, bringing them up to 3 digits. For single digit files I alter slightly and run again.

One nice thing about this script is that it works on subfolders.

I do have to admit to not understanding it completely. I have no real idea why doneis followed by  ' _ {} + . I guess that's the next thing I'll have to look up :-).

Body:
I have folders of images with names like HolidaySnapsJune-1.tif , HolidaySnapsMay-12.tif and HolidaySnaps2018-005.tif

I want to add one leading 0 to the integer section of the filename if it is 2 digits long, and I want to add two leading 00s if it is just one digit long.

I have tried variations of

find . -name '*\_[0-9][0-9].tif' -exec sh -c '
for fpath do
  echo mv "$fpath" "${fpath%/*}/${fpath##*/}"
done' _ {} +

But these put the leading zeros in front of the full file name instead of in front of the integer section.

I would love to do this is a bash script which would recursively work on folders so it's important that the difference in names preceeding the '-' is ignored or worked-around.

I'm on Windows and just have access to whatever is built into git-bashso bash, sed, awk etc.

Body:
So, after looking through the answers submitted here and elsewhere on SO this is what I ame up with:

find . -name '*\-[0-9][0-9].tif' -exec sh -c '
for f do
  mv "$f" "${f//\-/\-0}";
  echo "$f"
done' _ {} +

This works on files with two digits in the integer section, bringing them up to 3 digits. For single digit files I alter slightly and run again.

One nice thing about this script is that it works on subfolders.

I do have to admit to not understanding it completely. I have no real idea why doneis followed by  ' _ {} + . I guess that's the next thing I'll have to look up :-).


问:
How to filter metrics based on airflow dags in statsd?
I am looking for a way to filter out airflow metrics for other dags send over through StatsD. There is this document in airflow showing how to setup statsD which is responsible for metric gathering in airflow.
It is possible to filter for metric prefixes but this technically means it will send all those prefixes to statsd which will pose a great cost if it is happening for all the dags.

```<code>[metrics]
statsd_allow_list = scheduler,executor,dagrun
</code>```

Since I am using datadog it is very important to reduce cost by minimizing the metrics needed to send over to datadog.

Is there anyway to limit the metrics for a specific dag?

答:
I find the answer to this,
It is not possible to filter based off a dag name or a specific dag.
But we can include the complete metric name including the dag name in the filter list.

for example here is the metric name: dag.example_dag.some_task.duration
all need to do is to add this in the airflow.cfg like below:

```<code>[metrics]
statsd_allow_list = dag.example_dag.some_task.duration, <other filters>
</code>```

Body:
I am looking for a way to filter out airflow metrics for other dags send over through StatsD. There is this document in airflow showing how to setup statsD which is responsible for metric gathering in airflow.
It is possible to filter for metric prefixes but this technically means it will send all those prefixes to statsd which will pose a great cost if it is happening for all the dags.

[metrics]
statsd_allow_list = scheduler,executor,dagrun

Since I am using datadog it is very important to reduce cost by minimizing the metrics needed to send over to datadog.

Is there anyway to limit the metrics for a specific dag?

Body:
I find the answer to this,
It is not possible to filter based off a dag name or a specific dag.
But we can include the complete metric name including the dag name in the filter list.

for example here is the metric name: dag.example_dag.some_task.duration
all need to do is to add this in the airflow.cfg like below:

[metrics]
statsd_allow_list = dag.example_dag.some_task.duration, <other filters>


问:
Values are not inserting into the table (this only happens when I include the $token variable so I assume it is something to do with that variable)?
Here is my index.php code:

```<code>class DB {
    private static function connection() {
        $servername = "localhost";
        $username = "root";
        $password = "";
        $dbname="social";

        $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $conn;
    }
    public static function query($query, $params =array()) {
        $statement=self::connection()->prepare($query);
        $statement->execute($params);

        if (explode(' ', $query)[0] == 'SELECT') {
            $data = $statement->fetchAll();
            return $data;
        }
    }
}
</code>```

And here is my actlogin.php code:

```<code>include('index.php');

if(isset($_POST['login'])) {
 $username = $_POST['username'];
 $password = $_POST['password'];

if (DB::query('SELECT username FROM users WHERE username=:username', array(':username'=>$username))){

    if (password_verify($password, DB::query('SELECT password FROM users WHERE username=:username', array(':username'=>$username))[0]['password'])){
        echo 'Logged in!';

        $cstrong = True;
        $token = bin2hex(openssl_random_pseudo_bytes(64, $cstrong));
        echo $token;
        $user_id = DB::query('SELECT id FROM users WHERE username=:username', array(':username'=>$username))[0]['id'];
        DB::query('INSERT INTO login_tokens (token, user_id) VALUES (:token, :user_id)', array(':token'=>$token, ':user_id'=>$user_id));

    }else{
        echo 'Incorrect password!';
    }

} else {
    echo 'User not found!';
}

}
</code>```

I created a table in Sequel Pro called login_tokens with three columns: id, token, and user_id. Token has a unique key. I then made a relationship with the user_id column in the login_tokens table to the id column in the users table. I am following a tutorial and can't seem to figure out what I missed.

答:
For selects is query method and for insert-modify is execute

```<code>$slq = 'INSERT INTO login_tokens (token, user_id) VALUES (:token, :user_id)';
$stmt = $pdo->prepare($slq);
$stmt->bindValue(':token', $token);
$stmt->bindValue(':user_id', $user_id);
$stmt->execute();
</code>```

Body:
Here is my index.php code:

class DB {
    private static function connection() {
        $servername = "localhost";
        $username = "root";
        $password = "";
        $dbname="social";

        $conn = new PDO("mysql:host=$servername;dbname=$dbname", $username, $password);
        $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        return $conn;
    }
    public static function query($query, $params =array()) {
        $statement=self::connection()->prepare($query);
        $statement->execute($params);

        if (explode(' ', $query)[0] == 'SELECT') {
            $data = $statement->fetchAll();
            return $data;
        }
    }
}

And here is my actlogin.php code:

include('index.php');

if(isset($_POST['login'])) {
 $username = $_POST['username'];
 $password = $_POST['password'];

if (DB::query('SELECT username FROM users WHERE username=:username', array(':username'=>$username))){

    if (password_verify($password, DB::query('SELECT password FROM users WHERE username=:username', array(':username'=>$username))[0]['password'])){
        echo 'Logged in!';

        $cstrong = True;
        $token = bin2hex(openssl_random_pseudo_bytes(64, $cstrong));
        echo $token;
        $user_id = DB::query('SELECT id FROM users WHERE username=:username', array(':username'=>$username))[0]['id'];
        DB::query('INSERT INTO login_tokens (token, user_id) VALUES (:token, :user_id)', array(':token'=>$token, ':user_id'=>$user_id));

    }else{
        echo 'Incorrect password!';
    }

} else {
    echo 'User not found!';
}

}

I created a table in Sequel Pro called login_tokens with three columns: id, token, and user_id. Token has a unique key. I then made a relationship with the user_id column in the login_tokens table to the id column in the users table. I am following a tutorial and can't seem to figure out what I missed.

Body:
For selects is query method and for insert-modify is execute

$slq = 'INSERT INTO login_tokens (token, user_id) VALUES (:token, :user_id)';
$stmt = $pdo->prepare($slq);
$stmt->bindValue(':token', $token);
$stmt->bindValue(':user_id', $user_id);
$stmt->execute();


问:
How to install python3-lgpio on Ubuntu 20.04 on a Raspberry Pi
I'm following a tutorial on How to use the Raspberry Pi GPIO headers with ubuntu and one of the steps is installing python3-lgpio using

```<code>sudo apt install python3-lgpio
</code>```

and I get E: Unable to locate package python3-lgpio as the result.

I tried locating the package manually from here and installing it manually using sudo dpkg -i python3-lgpio and I get

```<code>dpkg: dependency problems prevent configuration of python3-lgpio:
python3-lgpio depends on python3 (>= 3.9~); however:
Version of python3 on system is 3.8.2-0ubuntu2.
</code>```

However, doing python -V outputs Python 3.9.10 as I had previously updated python on the Pi.

答:
I ran into this as well and ended up with an ugly work around for now. I loaded RPi.GPIO (https://pypi.org/project/RPi.GPIO/) and followed the usage instructions at https://sourceforge.net/p/raspberry-gpio-python/wiki/BasicUsage/

I was able to turn an LED on & off using IDLE. I did have to install the module with sudo and run IDLE with sudo. Yuck! Definitely a hack and I'll be following this to see if anyone has a better and more correct way to access the GPIO in 20.04.

Body:
I'm following a tutorial on How to use the Raspberry Pi GPIO headers with ubuntu and one of the steps is installing python3-lgpio using

sudo apt install python3-lgpio

and I get E: Unable to locate package python3-lgpio as the result.

I tried locating the package manually from here and installing it manually using sudo dpkg -i python3-lgpio and I get

dpkg: dependency problems prevent configuration of python3-lgpio:
python3-lgpio depends on python3 (>= 3.9~); however:
Version of python3 on system is 3.8.2-0ubuntu2.

However, doing python -V outputs Python 3.9.10 as I had previously updated python on the Pi.


问:
Pyyaml: Default dump behavior for inherited classes
I have a class that inherits from one of the built-ins:

from yaml import YAMLObject, dump
class D(dict, YAMLObject):
   yaml_tag = u'!!map'
   ...
```
<p>Is there a way to tell pyyaml that the dump of any instance of <code>D</code> should be treated like the parent (in this case dict)? I.e., I would like the following output:</p>
<pre class="lang-py prettyprint-override"><code>d = {'a':1}
print( dump(d) )
>>> a: 1
</code>```

Instead of

```<code>print( dump(D(d)) )
>>> !%21map {}
</code>```

As you can see I already tried assigning the class a default tag, but that did not quite work out.
Defining a custom dumper is unfortunately not an option.

答:
Short addition: Converting the data back to a dict first before dumping it is another elegant solution I completely missed:

d = D({'a':1})
print( dump(dict(d)) )
>>> a: 1
```

Body:
I have a class that inherits from one of the built-ins:

from yaml import YAMLObject, dump
class D(dict, YAMLObject):
   yaml_tag = u'!!map'
   ...

Is there a way to tell pyyaml that the dump of any instance of D should be treated like the parent (in this case dict)? I.e., I would like the following output:

d = {'a':1}
print( dump(d) )
>>> a: 1

Instead of

print( dump(D(d)) )
>>> !%21map {}

As you can see I already tried assigning the class a default tag, but that did not quite work out.
Defining a custom dumper is unfortunately not an option.


问:
Converting MyISAM to InnoDB in MySQL
I have a schema which was originally set up with MyISAM. I had relationships between tables which were not defined as foreign keys, but I would link the table with joins, etc. There were obviously no rules for cascading deletes/updates, etc...

I re-created the same DB schema with InnoDB, but this time I put the foreign keys into the create statements and defined the on update/delete rules.

I'm loading about 200,000 records into the DB with PHP from a CSV file. It was originally taking a few minutes but since I swapped to InnoDB the PHP script times out after 10 minutes with only ~7% of the CSV file processed.

I'm tempted to switch back to MyISAM without the relationships, however a better solution (if possible) would be to use MyISAM while initially populating the database and then switch back to InnoDB afterwards and let MySQL fix up the relationships. I don't know if this is possible, but I assume that if it is, MySQL can fix up it's own internal data structures faster than PHP insertion one-by-one.

Another thing to consider is that approximately once a year, we will need to re-load the set of 200,000 records and identify which ones have changed. It probably wouldn't be possible to switch from one engine to the other whenever we needed to do this.

Any pointers?

答:
Inserting data into the database can take up a long time if you're using one insert query per insert. It will speed up significantly when you use the format generated by mysqldump, like this:

```<code>INSERT INTO `table` (field1, field2, field3)
VALUES
(value, value, value),
(value, value, value),
(value, value, value);
</code>```

Also, if you'd like to insert it into myisam tables anyway, there's no problem either. Just make sure your foreign key integrity is right. After you've inserted all data, do this for all tables:

```<code>ALTER TABLE `table` ENGINE = innodb;
</code>```

ContentLicense: CC BY-SA 3.0

Title: Converting MyISAM to InnoDB in MySQL

Body:
Inserting data into the database can take up a long time if you're using one insert query per insert. It will speed up significantly when you use the format generated by mysqldump, like this:

INSERT INTO `table` (field1, field2, field3)
VALUES
(value, value, value),
(value, value, value),
(value, value, value);

Also, if you'd like to insert it into myisam tables anyway, there's no problem either. Just make sure your foreign key integrity is right. After you've inserted all data, do this for all tables:

ALTER TABLE `table` ENGINE = innodb;


问:
I want to apply, to a whole column, a formula that is already an arrayformula
I have a ledger with a bunch of expenses listed by date, category, and amount.
Expenses ledger

Separately I have an analytics sheet for one category, "Gas". I want the analytics sheet to show total gas expenditures month by month without having to update anything other than the ledger.
I can get a list of unique months with this formula:

=UNIQUE(ARRAYFORMULA(DATE(YEAR('Main Ledger'!A2:A), MONTH('Main Ledger'!A2:A), 1)))

This populates the months the way I want, and the list will automatically grow with the ledger. I put these in column A.

For each month, I want to compare every entry in the ledger against the date in column A and the category "Gas". I can do that for a single month with the following formula in column B:

=ArrayFormula(SUMIFS('Main Ledger'!D$2:D,MONTH('Main Ledger'!A$2:A),MONTH(A2),YEAR('Main Ledger'!A$2:A),YEAR(A2),'Main Ledger'!F$2:F,"Gas"))

Gasoline analytics

Because I have to use arrayformula to make the date comparison on the ledger, I'm having trouble figuring out how to then use arrayformula to automatically apply this monster formula to all of column B. As column A grows (automatically because of UNIQUE, I want column B to grow too.

I do not want to prepopulate column B and have a bunch of zeroes lying around, mainly because I will be using columns A and B to populate a chart.

答:
try in one go:

```<code>=QUERY({Sheet1!A2:D},
 "select month(Col1),sum(Col4)
  where Col4 is not null
  group by month(Col1)
  label month(Col1)'month'")
</code>```

update:

```<code>=INDEX(ARRAY_CONSTRAIN(QUERY({TEXT(Sheet1!A2:A, "mmmm"), Sheet1!A2:D},
 "select Col1,sum(Col5),month(Col2)
  where Col5 is not null
  group by month(Col2),Col1
  label Col1'month'"), 9^9, 2))
</code>```

Body:
try in one go:

=QUERY({Sheet1!A2:D},
 "select month(Col1),sum(Col4)
  where Col4 is not null
  group by month(Col1)
  label month(Col1)'month'")

update:

=INDEX(ARRAY_CONSTRAIN(QUERY({TEXT(Sheet1!A2:A, "mmmm"), Sheet1!A2:D},
 "select Col1,sum(Col5),month(Col2)
  where Col5 is not null
  group by month(Col2),Col1
  label Col1'month'"), 9^9, 2))


问:
Javascript alert function not displaying message after clicking button
Having an issue where I can't get the alert to display after clicking the button. I've edited the code from what it previously was according to the suggestions made and still not getting the alert to display. Any other thoughts on what the issue could be? I appreciate and thank you all for the help.</p>
```<code>    <!DOCTYPE html>
<html lang="en" dir="ltr">
  <head>
    <link href='https://fonts.googleapis.com/css?family=Open Sans' rel='stylesheet'>
    <meta charset="utf-8">

    <title>Pizzeria</title>

    <style type="text/css">

      body {
        margin: 40px;
        font-family: 'Open Sans';
      }
      #fieldSize, #fieldCrust {
        width: 150px;
        float: left;
        border: none;
      }
       #fieldToppings {
         width: 350px;
         border: none;

       }
       fieldset {
         margin-top: 20px;
       }
      #toppings1 {
        float: left;
      }
      label {
        display: inline-block;
        width: 150px;
        margin: 7px;
        text-align: left;
      }
      input[type="text"] {
        width: 250px;
      }
      div {
        padding: 10px;
      }
      #btnOrder {
        width: auto;
        border-radius: 10px;
      }

    </style>
    <script type="text/javascript">

      function orderSubmit() {
        var name = document.getElementById("txtName").value;
        var phone = document.getElementById("txtPhone").value;
        phone = '(' + phone.substring(0,3) + ')' + phone.substring(3,6) + '-' + phone.substring(6);
        var address = document.getElementById("txtAddress").value;

        var msg = name + ", your order is being prepared. \n";
        msg+= "Your order will be delivered at " + address;
        msg+= "Your contact infromation is: " + phone "\n";
        msg+= "Order details: \n \n";

        for(var i = 0; i < document.frm1.rdoSize.length; i++) {
           if(document.frm1.rdoSize[i].checked) {
             var radioStateSize = document.frm1.rdoSize[i].value;
           }
        }
        for(var j = 0; j < document.frm1.rdoCrust.length; j++) {
           if(document.frm1.rdoCrust[j].checked) {
             var radioStateCrust = document.frm1.rdoCrust[j].value;
           }
        }
        msg+= radioStateSize + ' ' + radioStateCrust + " pizza with the following toppings: \n";

        var chkToppings = document.frm1.chkToppings;

        for(k=0; k < document.frm1.chkToppings; k++) {
           if(document.frm1.chkToppings[k].checked) {
           msg += document.frm1.chkToppings[k].value + ' ';
           }
        }
        alert(msg);
      }

    </script>

  </head>

  <body>
    <fieldset id="main">
      <legend><h2>Pizza Order!</h2></legend>

      <form name="frm1">
        <div>
          <label for="lblName">Name:</label>
          <input type="text" id="txtName">
        </div>

        <div>
          <label for="lblPhone">Phone Number:</label>
          <input type="text" id="txtPhone">
        </div>

        <div>
          <label for="lblAddress">Address:</label>
          <input type="text" id="txtAddress">
        </div>

      <fieldset id="fieldSize">
        <legend><strong>Size</strong></legend>
          <input type="radio" name="rdoSize" value="Small" id="rdoSmall"> Small <br>
          <input type="radio" name="rdoSize" value="Medium" id="rdoMedium"> Medium <br>
          <input type="radio" name="rdoSize" value="Large" id="rdoLarge"> Large <br>
      </fieldset>

      <fieldset id="fieldCrust">
        <legend><strong>Crust</strong></legend>
          <input type="radio" name="rdoCrust" value="Thin" id="rdoThin"> Small <br>
          <input type="radio" name="rdoCrust" value="HandTossed" id="rdoHandTossed"> Hand Tossed <br>
          <input type="radio" name="rdoCrust" value="GF" id="rdoGF"> Gluten Free <br>
      </fieldset>

      <fieldset id="fieldToppings">
        <legend><strong>Toppings</strong></legend>
          <div id="toppings1">
            <input type="checkbox" name="chkToppings" id="chkPepperoni" value="Pepperoni"> Pepperoni <br>
            <input type="checkbox" name="chkToppings" id="chkSausage" value="Sausage"> Sausage <br>
            <input type="checkbox" name="chkToppings" id="chkChourico" value="Chourico"> Pepperoni <br>
            <input type="checkbox" name="chkToppings" id="chkChicken" value="Chicken"> Chicken <br>
            <input type="checkbox" name="chkToppings" id="chkAnchovies" value="Anchovies"> Anchovies <br>
          </div>
          <div id="toppings2">
            <input type="checkbox" name="chkToppings" id="chkMushrooms" value="Mushrooms"> Mushrooms <br>
            <input type="checkbox" name="chkToppings" id="chkPeppers" value="Peppers"> Peppers <br>
            <input type="checkbox" name="chkToppings" id="chkFeta" value="Feta"> Feta <br>
            <input type="checkbox" name="chkToppings" id="chkOlives" value="Olives"> Olives <br>
            <input type="checkbox" name="chkToppings" id="chkOnions" value="Onions"> Onions <br>
          </div>
      </fieldset>

      <input type="button" id="btnOrder" value="Order" onclick="orderSubmit()">

      </form>
    </fieldset>
  </body>
</html>
</code>```

答:
You have multiple problems

An extra semicolon here:

```<code>function orderSubmit(); {
</code>```

here:

```<code>for (var i = 0; i < document.frm1.rdoSize.length; i++); {
</code>```

and here:

```<code>for (var j = 0; j < document.frm1.rdoCrust.length; j++); {
</code>```

An extra point before brackets here:

```<code>if (document.frm1.rdoSize.[i].checked) {
</code>```

and here:

```<code>if (document.frm1.rdoCrust.[j].checked) {
</code>```

and a missing plus sign here:

```<code>msg += document.frm1.chkToppings[k].value + ' ';
</code>```

Body:
Having an issue where I can't get the alert to display after clicking the button. I've edited the code from what it previously was according to the suggestions made and still not getting the alert to display. Any other thoughts on what the issue could be? I appreciate and thank you all for the help.

    <!DOCTYPE html>

    <link href='https://fonts.googleapis.com/css?family=Open Sans' rel='stylesheet'>
    <meta charset="utf-8">

    <title>Pizzeria</title>

    <fieldset id="main">
      <legend>
Pizza Order!
</legend>

      <form name="frm1">

          Name:
          <input type="text" id="txtName">

          Phone Number:
          <input type="text" id="txtPhone">

          Address:
          <input type="text" id="txtAddress">

      <fieldset id="fieldSize">
        <legend>Size</legend>
          <input type="radio" name="rdoSize" value="Small" id="rdoSmall"> Small

          <input type="radio" name="rdoSize" value="Medium" id="rdoMedium"> Medium

          <input type="radio" name="rdoSize" value="Large" id="rdoLarge"> Large

      </fieldset>

      <fieldset id="fieldCrust">
        <legend>Crust</legend>
          <input type="radio" name="rdoCrust" value="Thin" id="rdoThin"> Small

          <input type="radio" name="rdoCrust" value="HandTossed" id="rdoHandTossed"> Hand Tossed

          <input type="radio" name="rdoCrust" value="GF" id="rdoGF"> Gluten Free

      </fieldset>

      <fieldset id="fieldToppings">
        <legend>Toppings</legend>

            <input type="checkbox" name="chkToppings" id="chkPepperoni" value="Pepperoni"> Pepperoni

            <input type="checkbox" name="chkToppings" id="chkSausage" value="Sausage"> Sausage

            <input type="checkbox" name="chkToppings" id="chkChourico" value="Chourico"> Pepperoni

            <input type="checkbox" name="chkToppings" id="chkChicken" value="Chicken"> Chicken

            <input type="checkbox" name="chkToppings" id="chkAnchovies" value="Anchovies"> Anchovies

            <input type="checkbox" name="chkToppings" id="chkMushrooms" value="Mushrooms"> Mushrooms

            <input type="checkbox" name="chkToppings" id="chkPeppers" value="Peppers"> Peppers

            <input type="checkbox" name="chkToppings" id="chkFeta" value="Feta"> Feta

            <input type="checkbox" name="chkToppings" id="chkOlives" value="Olives"> Olives

            <input type="checkbox" name="chkToppings" id="chkOnions" value="Onions"> Onions

      </fieldset>

      <input type="button" id="btnOrder" value="Order" onclick="orderSubmit()">

      </form>
    </fieldset>

Body:
You have multiple problems

An extra semicolon here:

function orderSubmit(); {

here:

for (var i = 0; i < document.frm1.rdoSize.length; i++); {

and here:

for (var j = 0; j < document.frm1.rdoCrust.length; j++); {

An extra point before brackets here:

if (document.frm1.rdoSize.[i].checked) {

and here:

if (document.frm1.rdoCrust.[j].checked) {

and a missing plus sign here:

msg += document.frm1.chkToppings[k].value + ' ';


问:
More elegant (shorter) solution for this regex pattern
I have spent three days banging my head on how to find a single solution to match anything between either single or double quotes with escaped single or doublequotes within actual source string and to replace matching text .. and I think that I have succeeded. Multi-line or single-line - it works. That is, this regex can be used to alter/change/sanitize 'text' or "text" or strings in other words, in any source code *(eg: file_get_contents ('some_class.php')) and to leave everything else untouched, assuming that code comments are already removed before such action.

Here is regex wrapped in singlequotes ..

```<code>'@"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'@msu'
</code>```

.. and here is regex wrapped within doublequotes.

```<code>"@\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'@msu"
</code>```

It is perfeclty matching with source code like this ...

// Very nasty php array

$Damn = [

  'a' => "' lorem ipsum '",

  'b' => '"\" ipsu\'m lorem  ',

  'c' => " \' YabadabaDooya \" ",

  'd\"' => '

     f"

     o\'"o

                 \'bar" ',

  'e' => "'",

  "f" => '"'

];

```

Since this is working as I expect, and I am actually not a PCRE guru (don't ask how much 'pain' I've had in the past three days D: until I came up to this solution), if there's anyone who knows how, and is willing to help by shrinking the above regex into more elegant/shorter solution, that would be superb. I assume that | (or) in the middle of the pattern can be placed onto beginning, just once .. and I tried God only knows what .. to accomplish that, but no luck.

So, the general question is - how would shorter variant of the above pattern look alike ?

答:
Here is my final (this time, really) answer to this problem/topic. In my previous post (that I deleted) I wrote that answer from Wahyu was the perfect one, but due to my natural lack of patience, that wasn't quite true (there's no such thing as "too much testing"), as further tests showed some innacuracy. Anyway, I still claim that Wahyu's approach - IS - the one that I was looking for and with just a tiny bit of modification, this time, I have succeeded in what I wanted.

Here's the original proposal by Wahyu that spared and saved my time - a lot!.

<<<REGEX

    (["'])((?:\\\1|(?:(?!\1)).)*)(\1)

REGEX;
```
<p>But that regex fails with something like this ...</p>
<pre class="lang-php prettyprint-override"><code>
  $ArrayWithCorrectSyntaxButIdioticStrings = [

    'a' => 'C:\\',

    'b' => "D:\\",

    'c' => " This i\s '
      '
      \'
      ' not a
      '
      \" love song"

  ];

</code>```

It failed on both 'a' and 'b' => values, meaning -> '\\'

But, with just a bit of modification, it truly became a - CHARM.

Here's the golden expression :)

Literal Variant (for online testing, etc.) nothing escaped.

<<<REGEX

    (["'`])((?:\\.[\1]*|(?:(?!\1)).)*)(\1)

REGEX;
```
<p>^^ for <code>regex101.com</code> tests <strong>gmus</strong> modifiers are required.</p>
<ul>
<li>And a simple string variant that safely can go into production:</li>
</ul>
<pre class="lang-php prettyprint-override"><code>
    $regex = '@(["\'`])((?:\\\\.[\\1]*|(?:(?!\\1)).)*)(\\1)@usm';

</code>```

And here's my own primary solution that also works correctly, maybe even more performant, but that I find ugly like a bI4tch. D:

```<code>    $regex = '@"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'
        . '|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''
        . '|`[^`\\\\]*(?:\\\\.[^`\\\\]*)*`'
        . '@usm';
</code>```

To summarize everything ...

Both regexes will find and match any text that is wrapped within backticks (php shell execution), singlequotes and doublequotes in one shot.

Tested over 15+ files that have over 2000 or 3000 lines of code (on Debian 10 with PHP 8.1 built-in web server).

Ideal for extracting or modifying strings over any source code file that uses single, doublequotes or backticks for string values/commands.

The main key difference is that Wahyu's proposal can be adjusted on just one place (1st capturing group), while my solution would take a bit more adjusting.

Edit:

After a while and/or in the meantime, as it seems like there's no point in looking for more solutions, as there are three valid variants, and the appropriate answer from sln been accepted, this question no longer falls into category for discussion.

Body:
I have spent three days banging my head on how to find a single solution to match anything between either single or double quotes with escaped single or doublequotes within actual source string and to replace matching text .. and I think that I have succeeded. Multi-line or single-line - it works. That is, this regex can be used to alter/change/sanitize 'text' or "text" or strings in other words, in any source code *(eg: file_get_contents ('some_class.php')) and to leave everything else untouched, assuming that code comments are already removed before such action.

Here is regex wrapped in singlequotes ..

'@"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\'@msu'

.. and here is regex wrapped within doublequotes.

"@\"[^\"\\\\]*(?:\\\\.[^\"\\\\]*)*\"|'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'@msu"

It is perfeclty matching with source code like this ...

// Very nasty php array

$Damn = [

  'a' => "' lorem ipsum '",

  'b' => '"\" ipsu\'m lorem  ',

  'c' => " \' YabadabaDooya \" ",

  'd\"' => '

     f"

     o\'"o

                 \'bar" ',

  'e' => "'",

  "f" => '"'

];

Since this is working as I expect, and I am actually not a PCRE guru (don't ask how much 'pain' I've had in the past three days D: until I came up to this solution), if there's anyone who knows how, and is willing to help by shrinking the above regex into more elegant/shorter solution, that would be superb. I assume that | (or) in the middle of the pattern can be placed onto beginning, just once .. and I tried God only knows what .. to accomplish that, but no luck.

So, the general question is - how would shorter variant of the above pattern look alike ?

Body:
Here is my final (this time, really) answer to this problem/topic. In my previous post (that I deleted) I wrote that answer from Wahyu was the perfect one, but due to my natural lack of patience, that wasn't quite true (there's no such thing as "too much testing"), as further tests showed some innacuracy. Anyway, I still claim that Wahyu's approach - IS - the one that I was looking for and with just a tiny bit of modification, this time, I have succeeded in what I wanted.

Here's the original proposal by Wahyu that spared and saved my time - a lot!.

<<<REGEX

    (["'])((?:\\\1|(?:(?!\1)).)*)(\1)

REGEX;

But that regex fails with something like this ...

  $ArrayWithCorrectSyntaxButIdioticStrings = [

    'a' => 'C:\\',

    'b' => "D:\\",

    'c' => " This i\s '
      '
      \'
      ' not a
      '
      \" love song"

  ];

It failed on both 'a' and 'b' => values, meaning -> '\\'

But, with just a bit of modification, it truly became a - CHARM.

Here's the golden expression :)

Literal Variant (for online testing, etc.) nothing escaped.

<<<REGEX

    (["'`])((?:\\.[\1]*|(?:(?!\1)).)*)(\1)

REGEX;

^^ for regex101.com tests gmus modifiers are required.

And a simple string variant that safely can go into production:

    $regex = '@(["\'`])((?:\\\\.[\\1]*|(?:(?!\\1)).)*)(\\1)@usm';

And here's my own primary solution that also works correctly, maybe even more performant, but that I find ugly like a bI4tch. D:

    $regex = '@"[^"\\\\]*(?:\\\\.[^"\\\\]*)*"'
        . '|\'[^\'\\\\]*(?:\\\\.[^\'\\\\]*)*\''
        . '|`[^`\\\\]*(?:\\\\.[^`\\\\]*)*`'
        . '@usm';

To summarize everything ...

Both regexes will find and match any text that is wrapped within backticks (php shell execution), singlequotes and doublequotes in one shot.

Tested over 15+ files that have over 2000 or 3000 lines of code (on Debian 10 with PHP 8.1 built-in web server).

Ideal for extracting or modifying strings over any source code file that uses single, doublequotes or backticks for string values/commands.

The main key difference is that Wahyu's proposal can be adjusted on just one place (1st capturing group), while my solution would take a bit more adjusting.

Edit:

After a while and/or in the meantime, as it seems like there's no point in looking for more solutions, as there are three valid variants, and the appropriate answer from sln been accepted, this question no longer falls into category for discussion.


问:
How to force Laravel API to always return JSON, no redirects
I have a Laravel application that I've built to act only as a JSON API. It has no views, and acts only to support our 1st party SPA. It uses Laravel 8, Fortify, and Sanctum. My SPA lives at my-app.test, and the api at api.my-app.test. The SPA works as expected. However, if I visit one of my authenticated API routes in the browser, e.g. api.my-app.test/someResource, I get an error page telling me "Route [login] not defined.", and the stack trace reveals this code:

vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php:393

protected function unauthenticated($request, AuthenticationException $exception)
{
  return $request->expectsJson()
    ? response()->json(['message' => $exception->getMessage()], 401)
    : redirect()->guest($exception->redirectTo() ?? route('login'));
}
```
<p>I have the following file where I've tried to override the <code>redirectTo</code> and <code>unauthenticated</code> methods, but it doesn't work:
<code>app/Http/Middleware/Authenticate.php</code></p>
<pre class="lang-php prettyprint-override"><code>protected function unauthenticated($request, array $guards): JsonResponse
{
  return response()->json(['message' => 'Unauthenticated.'], Response::HTTP_UNAUTHORIZED);
}

protected function redirectTo($request)
{
  return response()->json(['message' => 'Unauthenticated.'], Response::HTTP_UNAUTHORIZED);
}
</code>```

When I implement unauthenticated above, it seems it no longer authenticates any of my routes, hitting any API endpoint returns results that should be guarded. When I implement redirectTo above, I get another error saying "Header may not contain more than a single header, new line detected" and I'm not sure where to go from there.

What's the correct way to globally disable all views and redirects, and force Laravel to always return JSON? Is there a way to override expectsJson?

答:
You can also override unauthenticated function in app/Exceptions/Handler.php:

```<code>protected function unauthenticated($request, AuthenticationException $exception)
{
    return response()->json(['message' => $exception->getMessage()], 401);
}
</code>```

Body:
I have a Laravel application that I've built to act only as a JSON API. It has no views, and acts only to support our 1st party SPA. It uses Laravel 8, Fortify, and Sanctum. My SPA lives at my-app.test, and the api at api.my-app.test. The SPA works as expected. However, if I visit one of my authenticated API routes in the browser, e.g. api.my-app.test/someResource, I get an error page telling me "Route [login] not defined.", and the stack trace reveals this code:

vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php:393

protected function unauthenticated($request, AuthenticationException $exception)
{
  return $request->expectsJson()
    ? response()->json(['message' => $exception->getMessage()], 401)
    : redirect()->guest($exception->redirectTo() ?? route('login'));
}

I have the following file where I've tried to override the redirectTo and unauthenticated methods, but it doesn't work:
app/Http/Middleware/Authenticate.php

protected function unauthenticated($request, array $guards): JsonResponse
{
  return response()->json(['message' => 'Unauthenticated.'], Response::HTTP_UNAUTHORIZED);
}

protected function redirectTo($request)
{
  return response()->json(['message' => 'Unauthenticated.'], Response::HTTP_UNAUTHORIZED);
}

When I implement unauthenticated above, it seems it no longer authenticates any of my routes, hitting any API endpoint returns results that should be guarded. When I implement redirectTo above, I get another error saying "Header may not contain more than a single header, new line detected" and I'm not sure where to go from there.

What's the correct way to globally disable all views and redirects, and force Laravel to always return JSON? Is there a way to override expectsJson?

Body:
You can also override unauthenticated function in app/Exceptions/Handler.php:

protected function unauthenticated($request, AuthenticationException $exception)
{
    return response()->json(['message' => $exception->getMessage()], 401);
}


问:
best practice to use action url while calling ajax in cakePHP
I am using ajax with jQuery in my cakePHP application.

and my javascript function is placed inside a javascript file.

now in my local system the files are kept in "/sample" directory so the the path while i call the function will be

in ajax.js

```<code>$.post({url : "/sample/controller/action"})
</code>```

but after hosting it the url will become

```<code>$.post({url : "/mydomain.com/controller/action"})
</code>```

in cakePHP we $html->url to generate urls

but since this code is in js file i can't use that function

i don't want to change the all ajax action urls manually before hosting

答: in reply to Paul Dragoonis you can use $this->webroot if you use subfolders.

ContentLicense: CC BY-SA 2.5

Body:
I am using ajax with jQuery in my cakePHP application.

and my javascript function is placed inside a javascript file.

now in my local system the files are kept in "/sample" directory so the the path while i call the function will be

in ajax.js

$.post({url : "/sample/controller/action"})

but after hosting it the url will become

$.post({url : "/mydomain.com/controller/action"})

in cakePHP we $html->url to generate urls

but since this code is in js file i can't use that function

i don't want to change the all ajax action urls manually before hosting


问:
Laravel Saving certain files as a bin file
When 3d model files are uploaded to my site for some reason the extension is changed to .bin, This is causing issues with a javascript plugin that is used to display the file.

How can i prevent this from happening? I want the .glb or .gltf ext to remain the same.

Currently files that are uploaded the information is saved in the database with original name, extension, file path with link like 5454thghg.bin, and other info such as size.

Theres code included in the script so that when i go to download a file it gives me the file with the original name and extension that was uploaded so i know its possible to get the link

Here is the code.

```<code>public function upload(Request $request){
        $type = array(
            "jpg"=>"image",
            "jpeg"=>"image",
            "png"=>"image",
            "svg"=>"image",
            "webp"=>"image",
            "gif"=>"image",
            "mp4"=>"video",
            "mpg"=>"video",
            "mpeg"=>"video",
            "webm"=>"video",
            "ogg"=>"video",
            "avi"=>"video",
            "mov"=>"video",
            "flv"=>"video",
            "swf"=>"video",
            "mkv"=>"video",
            "wmv"=>"video",
            "wma"=>"audio",
            "aac"=>"audio",
            "wav"=>"audio",
            "mp3"=>"audio",
            "zip"=>"archive",
            "rar"=>"archive",
            "7z"=>"archive",
            "doc"=>"document",
            "txt"=>"document",
            "docx"=>"document",
            "pdf"=>"document",
            "csv"=>"document",
            "xml"=>"document",
            "ods"=>"document",
            "xlr"=>"document",
            "xls"=>"document",
            "xlsx"=>"document",
            "glb" => "cad",
            "gltf" => "cad",
            "usdz" => "cad",
            "3dm" => "Rhino",
            "stl" => "Stereolithography"
        );

        if($request->hasFile('aiz_file')){
            $upload = new Upload;
            $extension = strtolower($request->file('aiz_file')->getClientOriginalExtension());

            if(isset($type[$extension])){
                $upload->file_original_name = null;
                $arr = explode('.', $request->file('aiz_file')->getClientOriginalName());
                for($i=0; $i < count($arr)-1; $i++){
                    if($i == 0){
                        $upload->file_original_name .= $arr[$i];
                    }
                    else{
                        $upload->file_original_name .= ".".$arr[$i];
                    }
                }

                $path = $request->file('aiz_file')->store('uploads/all', 'local');
                $size = $request->file('aiz_file')->getSize();

                // Return MIME type ala mimetype extension
                $finfo = finfo_open(FILEINFO_MIME_TYPE);

                // Get the MIME type of the file
                $file_mime = finfo_file($finfo, base_path('public/').$path);

                if($type[$extension] == 'image' && get_setting('disable_image_optimization') != 1){
                    try {
                        $img = Image::make($request->file('aiz_file')->getRealPath())->encode();
                        $height = $img->height();
                        $width = $img->width();
                        if($width > $height && $width > 1500){
                            $img->resize(1500, null, function ($constraint) {
                                $constraint->aspectRatio();
                            });
                        }elseif ($height > 1500) {
                            $img->resize(null, 800, function ($constraint) {
                                $constraint->aspectRatio();
                            });
                        }
                        $img->save(base_path('public/').$path);
                        clearstatcache();
                        $size = $img->filesize();

                    } catch (\Exception $e) {
                        //dd($e);
                    }
                }

                if (env('FILESYSTEM_DRIVER') == 's3') {
                    Storage::disk('s3')->put(
                        $path,
                        file_get_contents(base_path('public/').$path),
                        [
                            'visibility' => 'public',
                            'ContentType' =>  $extension == 'svg' ? 'image/svg+xml' : $file_mime
                        ]
                    );
                    if($arr[0] != 'updates') {
                        unlink(base_path('public/').$path);
                    }
                }

                $upload->extension = $extension;
                $upload->file_name = $path;
                $upload->user_id = Auth::user()->id;
                $upload->type = $type[$upload->extension];
                $upload->file_size = $size;
                $upload->save();
            }
            return '{}';
        }
    }
</code>```

答:
From discussion in the comments, it turns out that neither the s3 code nor the image resizing code is relevant to this problem.  So the code exhibiting the problem can be boiled down to:

```<code>public function upload(Request $request){
    $type = array(
        // ... list of extensions ...
        "glb" => "cad",
    );

    $extension = strtolower($request->file('aiz_file')->getClientOriginalExtension());

    if ($request->hasFile('aiz_file')) {
        if (isset($type[$extension])) {

            // This line saves the uploaded file, and somehow changes extension
            $path = $request->file('aiz_file')->store('uploads/all', 'local');

        }
    }
}
</code>```

If that line is really causing the problem, it is not your own code, it is Laravel itself getting something wrong.  Checking the docs for file uploads, it says:

The file's extension will be determined by examining the file's MIME type

OK, so the MIME type is somehow confusing Laravel.  It seems like there is probably nothing we can do about that.  So what other options are there?

Checking the docs again, immediately following that section is a section on specifying your own file name.  You can do that with the storeAs() method, which takes a filename as the 2nd parameter:

```<code>$path = $request->file('aiz_file')->storeAs(
    'uploads/all', $request->file('aiz_file')->getClientOriginalName()
);
</code>```

If you want to keep the default Laravel behaviour of using a random hash as a filename, you can check the Laravel source on how they do that.  We can see store() uses hashName() to generate the filename, and that it does that like so (simplified):

```<code>$hash = Illuminate\Support\Str::random(40);
</code>```

So you could use something like:

```<code>$hash = Illuminate\Support\Str::random(40);
$extension = $request->file('aiz_file')->getClientOriginalExtension();

$path = $request->file('aiz_file')->storeAs(
    'uploads/all', $hash . '.' . $extension
);
</code>```

Body:
When 3d model files are uploaded to my site for some reason the extension is changed to .bin, This is causing issues with a javascript plugin that is used to display the file.

How can i prevent this from happening? I want the .glb or .gltf ext to remain the same.

Currently files that are uploaded the information is saved in the database with original name, extension, file path with link like 5454thghg.bin, and other info such as size.

Theres code included in the script so that when i go to download a file it gives me the file with the original name and extension that was uploaded so i know its possible to get the link

Here is the code.

public function upload(Request $request){
        $type = array(
            "jpg"=>"image",
            "jpeg"=>"image",
            "png"=>"image",
            "svg"=>"image",
            "webp"=>"image",
            "gif"=>"image",
            "mp4"=>"video",
            "mpg"=>"video",
            "mpeg"=>"video",
            "webm"=>"video",
            "ogg"=>"video",
            "avi"=>"video",
            "mov"=>"video",
            "flv"=>"video",
            "swf"=>"video",
            "mkv"=>"video",
            "wmv"=>"video",
            "wma"=>"audio",
            "aac"=>"audio",
            "wav"=>"audio",
            "mp3"=>"audio",
            "zip"=>"archive",
            "rar"=>"archive",
            "7z"=>"archive",
            "doc"=>"document",
            "txt"=>"document",
            "docx"=>"document",
            "pdf"=>"document",
            "csv"=>"document",
            "xml"=>"document",
            "ods"=>"document",
            "xlr"=>"document",
            "xls"=>"document",
            "xlsx"=>"document",
            "glb" => "cad",
            "gltf" => "cad",
            "usdz" => "cad",
            "3dm" => "Rhino",
            "stl" => "Stereolithography"
        );

        if($request->hasFile('aiz_file')){
            $upload = new Upload;
            $extension = strtolower($request->file('aiz_file')->getClientOriginalExtension());

            if(isset($type[$extension])){
                $upload->file_original_name = null;
                $arr = explode('.', $request->file('aiz_file')->getClientOriginalName());
                for($i=0; $i < count($arr)-1; $i++){
                    if($i == 0){
                        $upload->file_original_name .= $arr[$i];
                    }
                    else{
                        $upload->file_original_name .= ".".$arr[$i];
                    }
                }

                $path = $request->file('aiz_file')->store('uploads/all', 'local');
                $size = $request->file('aiz_file')->getSize();

                // Return MIME type ala mimetype extension
                $finfo = finfo_open(FILEINFO_MIME_TYPE);

                // Get the MIME type of the file
                $file_mime = finfo_file($finfo, base_path('public/').$path);

                if($type[$extension] == 'image' && get_setting('disable_image_optimization') != 1){
                    try {
                        $img = Image::make($request->file('aiz_file')->getRealPath())->encode();
                        $height = $img->height();
                        $width = $img->width();
                        if($width > $height && $width > 1500){
                            $img->resize(1500, null, function ($constraint) {
                                $constraint->aspectRatio();
                            });
                        }elseif ($height > 1500) {
                            $img->resize(null, 800, function ($constraint) {
                                $constraint->aspectRatio();
                            });
                        }
                        $img->save(base_path('public/').$path);
                        clearstatcache();
                        $size = $img->filesize();

                    } catch (\Exception $e) {
                        //dd($e);
                    }
                }

                if (env('FILESYSTEM_DRIVER') == 's3') {
                    Storage::disk('s3')->put(
                        $path,
                        file_get_contents(base_path('public/').$path),
                        [
                            'visibility' => 'public',
                            'ContentType' =>  $extension == 'svg' ? 'image/svg+xml' : $file_mime
                        ]
                    );
                    if($arr[0] != 'updates') {
                        unlink(base_path('public/').$path);
                    }
                }

                $upload->extension = $extension;
                $upload->file_name = $path;
                $upload->user_id = Auth::user()->id;
                $upload->type = $type[$upload->extension];
                $upload->file_size = $size;
                $upload->save();
            }
            return '{}';
        }
    }

Body:
From discussion in the comments, it turns out that neither the s3 code nor the image resizing code is relevant to this problem.  So the code exhibiting the problem can be boiled down to:

public function upload(Request $request){
    $type = array(
        // ... list of extensions ...
        "glb" => "cad",
    );

    $extension = strtolower($request->file('aiz_file')->getClientOriginalExtension());

    if ($request->hasFile('aiz_file')) {
        if (isset($type[$extension])) {

            // This line saves the uploaded file, and somehow changes extension
            $path = $request->file('aiz_file')->store('uploads/all', 'local');

        }
    }
}

If that line is really causing the problem, it is not your own code, it is Laravel itself getting something wrong.  Checking the docs for file uploads, it says:

The file's extension will be determined by examining the file's MIME type

OK, so the MIME type is somehow confusing Laravel.  It seems like there is probably nothing we can do about that.  So what other options are there?

Checking the docs again, immediately following that section is a section on specifying your own file name.  You can do that with the storeAs() method, which takes a filename as the 2nd parameter:

$path = $request->file('aiz_file')->storeAs(
    'uploads/all', $request->file('aiz_file')->getClientOriginalName()
);

If you want to keep the default Laravel behaviour of using a random hash as a filename, you can check the Laravel source on how they do that.  We can see store() uses hashName() to generate the filename, and that it does that like so (simplified):

$hash = Illuminate\Support\Str::random(40);

So you could use something like:

$hash = Illuminate\Support\Str::random(40);
$extension = $request->file('aiz_file')->getClientOriginalExtension();

$path = $request->file('aiz_file')->storeAs(
    'uploads/all', $hash . '.' . $extension
);


问:
Array not creating correctly in PowerShell
I have a script where I get all of the folders in d:\folder\*\*\ where the name is -like "*\Log".  I then split the folder paths apart to run through wmi to get the corresponding services.  After that I'm wanting to split apart the PathName property from $Services so I get everything before the \xxxxx.exe and add \log to the end of the result.  Eventually I'll then use those paths to do some compression and archiving of files via a gci.

For whatever reason when I run the script below I the previous loops $LocalLogVar without "log" appended and the current loops LocalLogVar with log appended.  I'm sure I'm doing something wrong that's blatantly obvious to somebody out there.  If somebody could point me in the right direction on this it'd be much appreciated!  I also apologize for the word vomit here, I've been looking at this script all day and my brain's pretty much used up.

A couple of notes:

The number of words in the paths vary which is why I can't manually do $LocalLogVar = "$Var1\$Var2\$Var3\Log"

If I don't have the [array] in front of $LogFolders the object type becomes a string and I get the previous loop's $LocalLogVar without "log" appended combined with the current loop's $LocalLogVar

I tried doing [collections.arraylist]$LogFolders=@() with no success

c:\folder is a shortcut to d:\folder, which is why there's c:\folder\xxx and d:\folder\xxx in the list below

SplitCount is -1 because I don't want the .exe from the path, I just want the folder structure

The naming convention for the string before .exe varies so I can't use an enumerated counter.

Example of first bullet:

```<code>word7-word8 #This is the previous loop's $LocalLogVar w/o "log" appended
C:\folder\word5\word6\word9-word8\log #This is the current loop's $LocalLogVar w/ "log" appended.
</code>```

Example of the second bullet:

```<code>word7-word8C:\folder\word5\word6\word9-word8\log
</code>```

What I should be getting:

```<code>D:\folder\word-anotherword\word7-word8\log
D:\folder\word-anotherword\word9-word8\log
C:\folder\word1\word7-word8\log
C:\folder\word1\word9-word8\log
C:\folder\word2\word7-word8\log
C:\folder\word2\word9-word8\log
D:\folder\word2\word10-word11\log
D:\folder\word2\word12-word8\log
C:\folder\word3\word7-word8\log
C:\folder\word3\word9-word8\log
D:\folder\word4\word7-word8\log
C:\folder\word4\word9-word8\log
C:\folder\word5\word6\word7-word8\log
C:\folder\word5\word6\word9-word8\log
C:\folder\word5\word6\word7-word8\log
C:\folder\word5\word6\word9-word8\log
</code>```

```<code>$Folders = Get-ChildItem D:\folder\*\*\ -Directory -Recurse -Verbose `
| Where-Object { $_.fullname -like "*\Log" }
$2 = @()
$LogFolders = @()

foreach ($folder in $folders) {
    $ServName = $folder.fullname.split('\')[2]
    $ServType = $folder.fullname.split('\')[3]
    $ServNameCheck = "*$($ServName.replace('-',' '))*"
    $ServTypeCheck = "*$($ServType.replace('-',' '))*"
    $PathName = Get-WmiObject -ClassName Win32_Service `
    | Where-Object { $_.caption -like "$ServNameCheck" -and $_.caption -like "$ServTypeCheck" } `
    | Select-Object Name, Caption, @{n = 'PathName'; e = { ($_.PathName).trim('"') } }
    $2 += $PathName
}
$Services = $2 | Sort-Object pathname | Get-Unique -AsString

foreach ($ServPath in $services.pathname) {
    $LocalLogVar = @()
    if (Get-Variable `
    | Where-Object { $_.name -match "^Split([0-9]|10)$" }) {
        Get-Variable `
    | Where-Object { $_.name -match "^Split([0-9]|10)$" } | Remove-Variable -Force
    }
    [int]$SplitCount = $ServPath.split('\').count
    [int]$SplitCountCheck = $SplitCount - 1
    $x = 0
    do {
        New-Variable -Name "Split$x" -Value "$($ServPath.split('\')[$x])"
        $RegEx = "Split$x"
        $LogFolderName = Get-Variable | Where-Object { $_.name -match $RegEx } | Select-Object value
        [string]$LogFolders = $LogFolderName.value.ToString()
        $LocalLogVar += $LogFolders + '\'
        $x++
    } until ($x -eq $SplitCountCheck)
    $LocalLogVar = $LocalLogVar
    $LocalLogVar = $LocalLogVar + "log"
    [array]$LogFolders += $LocalLogVar
}
</code>```

答:
Wow, so that's a script. Kind of hard to follow, since some of it seems needlessly complex. I'm not sure if it will accomplish what you're looking for, but that's because you were super vague with your folder descriptions. Do the folders always start like this:

D:\folder<Service Short Name><Service Long Name>...\logs

If not you could be in trouble. The last four items on your example list of what you expect to see don't look like they are like that. I think the way your folders are laid out are like this:

D:\folder...<Service Short Name><Service Long Name>\logs

The difference being where the extra folders are located. If they're before the service like I think they are your script will miss things.

Now, on to getting your list that you want. What I see from looking at your script is that you get a folder list for all folders under D:\folder\*\*\ named 'log'. Then you split out the 3rd and 4th folders to get a service's short name, and long name respectively. Then one by one you pull a list of all services from WMI, and filter for just the service that matches the name and caption (short name, and long name) referred to by the folders. After that you make sure you only have one listing of any given service.

Regarding this first part of the script, you can make it faster by letting the file system provider filter things for you. Instead of pulling a folder list of everything and then filtering for paths that end in '\log', you should use the -filter parameter of the Get-ChildItem cmdlet like this:

```<code>$Folders = Get-ChildItem C:\temp\*\*\ -Directory -Recurse -Verbose -Filter 'log'
</code>```

Then you should query WMI one time, save the result, then pick and choose from there based on your folders. Something like:

```<code>[array]$2 = foreach ($folder in $folders) {
    $ServName,$ServType = $folder.fullname.split('\')[2,3] -replace '-',' '
    $PathName = $AllServices |
        Where-Object { $_.caption -like "*$ServName*" -and $_.caption -like "*$ServType*" } |
        Select-Object Name, Caption, @{n = 'PathName'; e = { $_.PathName -replace '^(\w\S+) .*','$1' -replace '^([''"])([^\1]+)\1.*','$2' } }
}
$Services = $2 | Sort-Object pathname | Get-Unique -AsString
</code>```

I did a little regex magic to clean up the pathname instead of just .trim('"') since this gets rid of parameters in the service execution, and cleans paths that are enclosed in single quotes not just double quotes. If what you have works for you feel free to keep it, but this is a little more capable. It may be worth noting that Get-Unique is case sensitive, so 'C:\folder\word3\word9-word8' and 'C:\folder\word3\word9-Word8' are different. You might want to do a .ToUpper() on your paths before you look for unique ones.

Once you have your array of services you loop through them, splitting the file path, reassembling it, and finally adding 'log' to the end of it. That was your way to remove the executable from the path. There's a cmdlet that was designed to do just that: split-path. Use that with Join-Path and that whole last loop gets much simpler:

```<code>[array]$LogFolders = foreach ($ServPath in $services.pathname) {
    Join-Path (Split-Path $ServPath) 'log'
}
</code>```

Lastly, try not to use +=, since PowerShell has to rebuild the whole array each time you do that. You'll notice I moved the $Variable =  bit outside the loop in places that you do that.

Body:
I have a script where I get all of the folders in d:\folder\*\*\ where the name is -like "*\Log".  I then split the folder paths apart to run through wmi to get the corresponding services.  After that I'm wanting to split apart the PathName property from $Services so I get everything before the \xxxxx.exe and add \log to the end of the result.  Eventually I'll then use those paths to do some compression and archiving of files via a gci.

For whatever reason when I run the script below I the previous loops $LocalLogVar without "log" appended and the current loops LocalLogVar with log appended.  I'm sure I'm doing something wrong that's blatantly obvious to somebody out there.  If somebody could point me in the right direction on this it'd be much appreciated!  I also apologize for the word vomit here, I've been looking at this script all day and my brain's pretty much used up.

A couple of notes:

The number of words in the paths vary which is why I can't manually do $LocalLogVar = "$Var1\$Var2\$Var3\Log"

If I don't have the [array] in front of $LogFolders the object type becomes a string and I get the previous loop's $LocalLogVar without "log" appended combined with the current loop's $LocalLogVar

I tried doing [collections.arraylist]$LogFolders=@() with no success

c:\folder is a shortcut to d:\folder, which is why there's c:\folder\xxx and d:\folder\xxx in the list below

SplitCount is -1 because I don't want the .exe from the path, I just want the folder structure

The naming convention for the string before .exe varies so I can't use an enumerated counter.

Example of first bullet:

word7-word8 #This is the previous loop's $LocalLogVar w/o "log" appended
C:\folder\word5\word6\word9-word8\log #This is the current loop's $LocalLogVar w/ "log" appended.

Example of the second bullet:

word7-word8C:\folder\word5\word6\word9-word8\log

What I should be getting:

D:\folder\word-anotherword\word7-word8\log
D:\folder\word-anotherword\word9-word8\log
C:\folder\word1\word7-word8\log
C:\folder\word1\word9-word8\log
C:\folder\word2\word7-word8\log
C:\folder\word2\word9-word8\log
D:\folder\word2\word10-word11\log
D:\folder\word2\word12-word8\log
C:\folder\word3\word7-word8\log
C:\folder\word3\word9-word8\log
D:\folder\word4\word7-word8\log
C:\folder\word4\word9-word8\log
C:\folder\word5\word6\word7-word8\log
C:\folder\word5\word6\word9-word8\log
C:\folder\word5\word6\word7-word8\log
C:\folder\word5\word6\word9-word8\log

$Folders = Get-ChildItem D:\folder\*\*\ -Directory -Recurse -Verbose `
| Where-Object { $_.fullname -like "*\Log" }
$2 = @()
$LogFolders = @()

foreach ($folder in $folders) {
    $ServName = $folder.fullname.split('\')[2]
    $ServType = $folder.fullname.split('\')[3]
    $ServNameCheck = "*$($ServName.replace('-',' '))*"
    $ServTypeCheck = "*$($ServType.replace('-',' '))*"
    $PathName = Get-WmiObject -ClassName Win32_Service `
    | Where-Object { $_.caption -like "$ServNameCheck" -and $_.caption -like "$ServTypeCheck" } `
    | Select-Object Name, Caption, @{n = 'PathName'; e = { ($_.PathName).trim('"') } }
    $2 += $PathName
}
$Services = $2 | Sort-Object pathname | Get-Unique -AsString

foreach ($ServPath in $services.pathname) {
    $LocalLogVar = @()
    if (Get-Variable `
    | Where-Object { $_.name -match "^Split([0-9]|10)$" }) {
        Get-Variable `
    | Where-Object { $_.name -match "^Split([0-9]|10)$" } | Remove-Variable -Force
    }
    [int]$SplitCount = $ServPath.split('\').count
    [int]$SplitCountCheck = $SplitCount - 1
    $x = 0
    do {
        New-Variable -Name "Split$x" -Value "$($ServPath.split('\')[$x])"
        $RegEx = "Split$x"
        $LogFolderName = Get-Variable | Where-Object { $_.name -match $RegEx } | Select-Object value
        [string]$LogFolders = $LogFolderName.value.ToString()
        $LocalLogVar += $LogFolders + '\'
        $x++
    } until ($x -eq $SplitCountCheck)
    $LocalLogVar = $LocalLogVar
    $LocalLogVar = $LocalLogVar + "log"
    [array]$LogFolders += $LocalLogVar
}

Body:
Wow, so that's a script. Kind of hard to follow, since some of it seems needlessly complex. I'm not sure if it will accomplish what you're looking for, but that's because you were super vague with your folder descriptions. Do the folders always start like this:

D:\folder<Service Short Name><Service Long Name>...\logs

If not you could be in trouble. The last four items on your example list of what you expect to see don't look like they are like that. I think the way your folders are laid out are like this:

D:\folder...<Service Short Name><Service Long Name>\logs

The difference being where the extra folders are located. If they're before the service like I think they are your script will miss things.

Now, on to getting your list that you want. What I see from looking at your script is that you get a folder list for all folders under D:\folder\*\*\ named 'log'. Then you split out the 3rd and 4th folders to get a service's short name, and long name respectively. Then one by one you pull a list of all services from WMI, and filter for just the service that matches the name and caption (short name, and long name) referred to by the folders. After that you make sure you only have one listing of any given service.

Regarding this first part of the script, you can make it faster by letting the file system provider filter things for you. Instead of pulling a folder list of everything and then filtering for paths that end in '\log', you should use the -filter parameter of the Get-ChildItem cmdlet like this:

$Folders = Get-ChildItem C:\temp\*\*\ -Directory -Recurse -Verbose -Filter 'log'

Then you should query WMI one time, save the result, then pick and choose from there based on your folders. Something like:

[array]$2 = foreach ($folder in $folders) {
    $ServName,$ServType = $folder.fullname.split('\')[2,3] -replace '-',' '
    $PathName = $AllServices |
        Where-Object { $_.caption -like "*$ServName*" -and $_.caption -like "*$ServType*" } |
        Select-Object Name, Caption, @{n = 'PathName'; e = { $_.PathName -replace '^(\w\S+) .*','$1' -replace '^([''"])([^\1]+)\1.*','$2' } }
}
$Services = $2 | Sort-Object pathname | Get-Unique -AsString

I did a little regex magic to clean up the pathname instead of just .trim('"') since this gets rid of parameters in the service execution, and cleans paths that are enclosed in single quotes not just double quotes. If what you have works for you feel free to keep it, but this is a little more capable. It may be worth noting that Get-Unique is case sensitive, so 'C:\folder\word3\word9-word8' and 'C:\folder\word3\word9-Word8' are different. You might want to do a .ToUpper() on your paths before you look for unique ones.

Once you have your array of services you loop through them, splitting the file path, reassembling it, and finally adding 'log' to the end of it. That was your way to remove the executable from the path. There's a cmdlet that was designed to do just that: split-path. Use that with Join-Path and that whole last loop gets much simpler:

[array]$LogFolders = foreach ($ServPath in $services.pathname) {
    Join-Path (Split-Path $ServPath) 'log'
}

Lastly, try not to use +=, since PowerShell has to rebuild the whole array each time you do that. You'll notice I moved the $Variable =  bit outside the loop in places that you do that.