Jak nazwać funkcję znajdującą dopasowania, ale wybaczającą błędy?

0

Właśnie refaktoruję bibliotekę T-Regx, bo chcę szybko wydać wersję 1.0.

Mam tam funkcję Pattern.match(string $subject): Matcher, która zwraca matcher, który pozwala iterować bo znalezionych wystąpieniach wyrażenia regularnego, i rzuca odpowiedni wyjątek jeśli coś się nie udało (backtracking, recursja, jit limit, etc.)

Używa się go mniej więcej tak:

$pattern = new Patter('[a-z]+', 'i');
$matcher = $pattern->match('some string here');

foreach ($matcher as $match) {

}

if (!$match->test()) {
  echo 'nothing found';
}
Nowa funkcja

Chcę teraz dodać funkcje która "wybacza" errory, tzn. znajduje wszystkie matche które się udało znaleźć, i nawet jeśli jest jakiś błąd (backtrack, rekrursja) to po prostu ten match jest pomijany i zwracane są te które udało się znaleźć. Zastanawiam się jak ją nazwać? Zaznaczcie kilka opcji które wam się podobają w ankiecie. Można też sugerować nowe.

0

Pattern.infatuate()

1

może matchOmitMaliciousInput? Masz jakąś dobrą nazwę na nazwanie zbiórczo wszystkich sytuacji, gdzie będziemy mieli błąd

Tak czy owak moja wersja pasuje mi najbardzie, bo chyba o to chodzi głównie: regex według nas jest ok, tylko input może być źle skrojony pod nasz pattern

1
  • matchTolerant

  • indianMatch

  • matchHappily

  • matchRoughly

  • matchCarefree

  • matchIndolently

5

Zamiast dodawać osobną funkcję można by rozważyć dodanie opcjonalnego parametru do istniejącej, który pozwala na wybór strategii radzenia sobie z błędami.

0
Spearhead napisał(a):

Zamiast dodawać osobną funkcję można by rozważyć dodanie opcjonalnego parametru do istniejącej, który pozwala na wybór strategii radzenia sobie z błędami.

No na pewno. Dzięki za tak "super" propozycje.

4
Riddle napisał(a):
Spearhead napisał(a):

Zamiast dodawać osobną funkcję można by rozważyć dodanie opcjonalnego parametru do istniejącej, który pozwala na wybór strategii radzenia sobie z błędami.

No na pewno. Dzięki za tak "super" propozycje.

Ten komentarz jest bezwartościowy bez wyjaśnienia dlaczego uważasz propozycję za niepoprawną.

Nie wiem po co ta nieprofesjonalna uszczypliwość. Jak ktoś ci robi code review to też tak reagujesz pod każdym komentarzem? Ktoś chce z dobrej woli pomóc, doradzić, podsunąć pomysł i tylko mu się dostaje. Proponuję popracować nad skillami miękkimi, bo z tego co widzę już któryś raz się wykazujesz kompletnie niepotrzebną opryskliwością.

0
Spearhead napisał(a):
Riddle napisał(a):
Spearhead napisał(a):

Zamiast dodawać osobną funkcję można by rozważyć dodanie opcjonalnego parametru do istniejącej, który pozwala na wybór strategii radzenia sobie z błędami.

No na pewno. Dzięki za tak "super" propozycje.

Ten komentarz jest bezwartościowy bez wyjaśnienia dlaczego uważasz propozycję za niepoprawną.

Nie wiem po co ta nieprofesjonalna uszczypliwość. Jak ktoś ci robi code review to też tak reagujesz pod każdym komentarzem? Ktoś chce z dobrej woli pomóc, doradzić, podsunąć pomysł i tylko mu się dostaje. Proponuję popracować nad skillami miękkimi, bo z tego co widzę już któryś raz się wykazujesz kompletnie niepotrzebną opryskliwością.

Po pierwsze temat dotyczy tego jak nazwać funkcję, i właściwie to tylko opinia na ten temat mnie interesuje. Wszystko inne to w moich oczach off-topic.

Jeśli koniecznie chcesz dostać odpowiedź, to jest kilka powodów czemu uważam że parametr to zły pomysł:

  • Po pierwsze, dodanie parametru komplikuje interfejs, bo wtedy pojedyncza funkcja ma więcej odpowiedzialności (więc łamie SRP).
  • Po drugie, zasadność tego parametru praktycznie nie istnieje, ponieważ to nie jest wartość która byłaby przyjęta od użytkownika lub z innego źródła, tylko zawsze jest znana w compile-time'ie - w miejscu gdzie obsłużony jest wyjątek byłaby jedna wartość, w miejscu w którym nie, nie byłoby jej. Więc nie ma powodu żeby to był parametr.
  • Po trzecie, aktualnie są dwie opcje "reagowania na błędy" jak to nazwałeś, więc musiałby to być albo bool, albo enum z dwoma wartościami, albo magiczna wartość int lub string lub inny prymityw - każde jest słabym podejściem.
  • Po czwarte, ta funkcja już ma 3 argumenty, string subject, int offset oraz int limit, dodawanie czwartego to byłby nadmiar.
  • Po piąte, dwie funkcje nie są niczym złym, a wręcz przeciwnie - dają szansę na nadanie odpowiedniej nazwy różnym zachowaniom, co zwiększa czytelność. Funkcje są podobne, dlatego ich początek nazwy jest taki sam: match...(), ale jednak działają w inny sposób, dlatego końcówka nazwy powinna wskazywać na ich różnice. Oczywiście osoba pisząca kod (ja) musi włożyć trud w odpowiednie nazwanie funkcji (co nie jest łatwe), ale za to czytający będą mieli dużo łatwiejsze zadanie w rozpoznaniu co ten kod robi, więc kod będzie dużo czytelniejszy; a na tym mi zależy.
  • Jesli to nie wystarczy, to po szóste - gdybym chciał dodać kolejny sposób obsługi błędów, to zamiast po prostu dodania nowej funkcji, musiałbym edytować istniejącą (czyli łamie Open/Close).
  • Jeśli nadal to nie wystarczy, to po siódme - parametry uławiają przekazywanie dynamicznych wartości do funkcji, co jest całkowicie niepotrzebne w tym przypadku.
  • Po ósme, jeśli znajdziemy się w sytuacji w której już istnieją dwie funkcje, to nie ma (a przynajmniej ja nie widzę) żadnego sensownego argumentu za tym żeby je połączyć w jedną i sterować nimi parametrem. Masz jakiś?
  • Po dziewiąte, funkcje są używane do podobnego celu, ale wykorzystuje się je inaczej - w jednej trzeba obsłużyć wyjątki w drugiej nie; więc te funkcje tylko z pozoru są podobne, ich użycie jest inne - bo jedno wymaga try/catcha, a drugie nie. Więc nie ma powodu żeby to była ta sama funkcja.

Dodatkowo, jest pewna miskoncepcja - to nie jest tak że jak dwie funkcjonalności są w jednej funkcji, to jest mniej kodu. To jest popularna pułapka, może się komuś wydawać że jak masz dwie funkcje zamiast jednej, to niby masz 2x więcej kodu Niestety to nie jest prawdą - kodu jest tyle samo, bo nadal są dwie funkcjonalności. Pytanie tylko czy będziemy mieć (dla przykładu) jedną funkcję na 100 linijek, czy 2 funkcje na 50 linijek. Oczywiście to drugie, w tym wypadku to lepsze wyjście.

Innymi słowy dodanie parametru nie ma żądnych zalet, a ma same wady. Byłem uszczypliwy dlatego że pomysł z parametrem wydał mi się tak oczywiście absurdalny, że nie sądziłem że wymaga to wyjaśnienia. Przepraszam za to.

2

Pattern.matchContinueOnErrors()
Pattern.matchValidContinueOnErrors()

1
dmw napisał(a):

Pattern.matchContinueOnErrors()
Pattern.matchValidContinueOnErrors()

Dzięki, dobre propozycje, podobają mi się.

Chociaż zamiast matchContinueOnErrors() lepsze byłoby matchContinueOnError().

2

@Spearhead:

Zamiast dodawać osobną funkcję można by rozważyć dodanie opcjonalnego parametru do istniejącej, który pozwala na wybór strategii radzenia sobie z błędami.

Ten komentarz jest bezwartościowy bez wyjaśnienia dlaczego uważasz propozycję za niepoprawną.

Nie wiem po co ta nieprofesjonalna uszczypliwość. Jak ktoś ci robi code review to też tak reagujesz pod każdym komentarzem? Ktoś chce z dobrej woli pomóc, doradzić, podsunąć pomysł i tylko mu się dostaje. Proponuję popracować nad skillami miękkimi, bo z tego co widzę już któryś raz się wykazujesz kompletnie niepotrzebną opryskliwością.

Zabawne jest to, że w BCLu .NETa nierzadko właśnie tak to jest rozwiązane i też pomyślałem o tym jako o sensownej opcji, a przynajmniej rozważenia (bo przecież wiadomo że mało kto robi tak dobre API jak ludzie tworzący BCL .neta)

np.

public string[] Split (char separator, StringSplitOptions options = System.StringSplitOptions.None);

Gdzie "StringSplitOptions"

  [Flags]
  public enum StringSplitOptions
  {
      /// <summary>
      /// Do not transform the results. This is the default behavior.
      /// </summary>
      None = 0,

      /// <summary>
      /// Remove empty (zero-length) substrings from the result.
      /// </summary>
      /// <remarks>
      /// If <see cref="RemoveEmptyEntries"/> and <see cref="TrimEntries"/> are specified together,
      /// then substrings that consist only of whitespace characters are also removed from the result.
      /// </remarks>
      RemoveEmptyEntries = 1,

      /// <summary>
      /// Trim whitespace from each substring in the result.
      /// </summary>
      TrimEntries = 2
  }

czy jak już w temacie regexa ;)

public Regex (string pattern, System.Text.RegularExpressions.RegexOptions options);

enum RegexOptions
{
    /// <summary>Use default behavior.</summary>
    None                    = 0x0000,

    /// <summary>Use case-insensitive matching.</summary>
    IgnoreCase              = 0x0001, // "i"

    /// <summary>
    /// Use multiline mode, where ^ and $ match the beginning and end of each line
    /// (instead of the beginning and end of the input string).
    /// </summary>
    Multiline               = 0x0002, // "m"

    /// <summary>
    /// Do not capture unnamed groups. The only valid captures are explicitly named
    /// or numbered groups of the form (?&lt;name&gt; subexpression).
    /// </summary>
    ExplicitCapture         = 0x0004, // "n"

    /// <summary>Compile the regular expression to Microsoft intermediate language (MSIL).</summary>
    Compiled                = 0x0008,

    /// <summary>
    /// Use single-line mode, where the period (.) matches every character (instead of every character except \n).
    /// </summary>
    Singleline              = 0x0010, // "s"

    /// <summary>Exclude unescaped white space from the pattern, and enable comments after a number sign (#).</summary>
    IgnorePatternWhitespace = 0x0020, // "x"

    /// <summary>Change the search direction. Search moves from right to left instead of from left to right.</summary>
    RightToLeft             = 0x0040,

    /// <summary>Enable ECMAScript-compliant behavior for the expression.</summary>
    ECMAScript              = 0x0100,

    /// <summary>Ignore cultural differences in language.</summary>
    CultureInvariant        = 0x0200,

    /// <summary>
    /// Enable matching using an approach that avoids backtracking and guarantees linear-time processing
    /// in the length of the input.
    /// </summary>
    /// <remarks>
    /// Certain features aren't available when this option is set, including balancing groups,
    /// backreferences, positive and negative lookaheads and lookbehinds, and atomic groups.
    /// Capture groups are also ignored, such that the only capture available is that for
    /// the top-level match.
    /// </remarks>
    NonBacktracking         = 0x0400,
}

I takie Options można wtedy ORować

RegexOptions options = RegexOptions.IgnoreCase | RegexOptions.Compiled;
0

@Riddle: może match i unsafeMatch ?

3

Jest jakiś BDD, w którym taki przypadek się przydaje, gdzie regex się wykłada, ale wcześniej znalazł jakieś dopasowania przed tym za nim się wywalił?
Jak się wywaliło to znaczy, że ktoś jakiś malicous input wrzucił.

Znaczy pytam tak, bo akurat nie mam pomysłu czy by mi się kiedyś przydało, a zawsze można innych ludzi popytać, inne doświadczenie.

1
Hodor napisał(a):

@Riddle: może match i unsafeMatch ?

Dodałem Pattern.matchUnsafe() do ankiety.

GodOfCode. napisał(a):

Jest jakiś BDD, w którym taki przypadek się przydaje, gdzie regex się wykłada, ale wcześniej znalazł jakieś dopasowania przed tym za nim się wywalił?
Jak się wywaliło to znaczy, że ktoś jakiś malicous input wrzucił.

Znaczy pytam tak, bo akurat nie mam pomysłu czy by mi się kiedyś przydało, a zawsze można innych ludzi popytać, inne doświadczenie.

A jaki to ma związek z tematem? W temacie chodzi o nazwę funkcji, nie wiem czemu to jest takie trudne do zrozumienia.

Już nie mówiąc o tym że nie ma czegoś takiego jak malicious input. Najwyżej jest input poprawnie albo niepoprawnie obsłużony.

1

Pattern.matchErrorTolerant
Pattern.matchTolerant
Pattern.tolerantMatch

1

Może matchIterator i zwrócić generator, który będzie zwracał znalezione obiekty aż do końca stream lub exception w razie błędu.

0

Mógłbyś podać jakiś przykład bo mimo przeczytania całego wątku dalej nie rozumiem co ta funkcja ma robić.
Ma pozwolić na podanie nieprawidłowego regexa? W celu debugowania i tworzenia regexów czy jak? Użycie czegoś takiego na produkcji wydaje mi się proszeniem się o problemy, przypasowanie albo jest albo nie ma. Jak część przypasowania jest opcjonalna to regex przecież pozwala na określenie tego.

Nikczemnym rywalem Mario jest Wario więc może .match i .watch albo nawet .holdMyBeerAndWatch / .holdMyBeerAndMatch ?

0
obscurity napisał(a):

Mógłbyś podać jakiś przykład bo mimo przeczytania całego wątku dalej nie rozumiem co ta funkcja ma robić.
Ma pozwolić na podanie nieprawidłowego regexa? W celu debugowania i tworzenia regexów czy jak?

Nie, ma przyjąć poprawny regexp i poprawny subject. Use case to np kiedy pattern jest skomplikowany, i dostaniemy subject który jest długi - wtedy mamy catastrophic backtracking i aktualnie biblioteka rzuca wyjątek. Teraz chcemy funkcje która po prostu pominie ten kawałek stringa, i zwróci te wartości które udało się znaleźć.

0

match oraz matchSkipUnsafeBacktracking?

wtedy ta nazwa by chociaż coś mówiła, i user wie o co chodzi, a nie jakieś "gracefully", "partial" czy "ignore errors" jakie errors? cholera wie, trzeba zerknąć w docsy

2

matchFuzzy

0
Riddle napisał(a):

Nie, ma przyjąć poprawny regexp i poprawny subject. Use case to np kiedy pattern jest skomplikowany, i dostaniemy subject który jest długi - wtedy mamy catastrophic backtracking i aktualnie biblioteka rzuca wyjątek. Teraz chcemy funkcje która po prostu pominie ten kawałek stringa, i zwróci te wartości które udało się znaleźć.

A w jaki sposób się to dzieje? PHP na to pozwala czy implementujesz własny silnik regexa? Takie rozwiązanie to trochę półśrodek, ciężko mi wyobrazić sobie zastosowanie w którym częściowe przypasowanie może nam się do czegoś przydać, nie wiedząc jaka część została pominięta.

Przykładowo w .NET od wersji 7 jest dostępny nowy tryb NonBacktracking w którym catastrophic backtracking nigdy nie występuje a regexy zawsze wykonują się w czasie liniowym. Tryb non-backtracking nie obsługuje za to

  • Atomic groups
  • Backreferences
  • Balancing groups
  • Conditionals
  • Lookarounds
  • Start anchors

Czyli rzeczy których 99% userów nie używa lub używa bardzo rzadko, ale moim zdaniem taka opcja ma dużo więcej sensu niż przerywanie działania regexa w tak naprawdę losowym momencie.
Try NonBacktracking nie jest odpowiednikiem atomic groups, przykładowo znajdzie normalnie dopasowanie w patternie:

a(bc|b)c

zarówno do abcc i abc. Atomic group znalazłoby tylko abcc

0

@obscurity: Czego nie rozumiesz, jak Ci mówię że ten wątek nie dotyczy w żadnym stopniu opinii o działaniu tej metody, a tylko i wyłącznie jej nazwy?

1

@Riddle: bo to jest problem X/Y

0

@anonimowy: Pracuję nad tą biblioteką jakieś 5 lat, wydałem jej 80 wersji, i przeklepałem te funkcje do regexpów wzdłuż i w szerz spokojnie jakieś 100 razy. @obscurity przeczytał ten temat, nie skumał idei tej funkcji, i zasguerował że w C# jest tryb non-backtracking.

Mamy kilkadziesiąt stron rozmowy nt designu tej funkcji, i o tym jak podejść do problemu z runtime'owymi błędami w zaprojektowaniu tej funkcji, zajęło to jakieś kilka miesięcy żeby dotrzeć do jakiegoś sensownego konsensusu. I teraz @anonimowy pisze "x/y". No ciekawe. Nie sądzę że ktokolwiek tutaj ma ochotę spędzić kilkagodzin dzienne przez pare miesięcy, żeby przejść przez taki brainstorming ponownie, rozważając wszystkie możliwe edge'case.y

Ale w skrócie, czemu uważam że pomysł od @obscurity jest słaby to, funkcja matchIgnoreErrors(), nie jest tylko do backtrackingu, ale również innych błędów, np do przekroczenia limitu zagnieżdżenia, do przepełnienia stosu just-in-time compiler, i wielu innych potencjalnych przeszkadzajek. w sumie jest ich jakieś 7, także pomysł "dodaj tryb non-backtracking" nie wiele dodaje.

Doceniam ciekawość forumowiczów nt tej funkcji, i fajnie że macie ochotę robić brainstorming nt tego jak mogłaby działać, ale to zostało już zrobione z zespołem, także dzięki. Teraz szukam tylko nazwy funkcji, także doceniłbym gdyby wszyscy zostali przy temacie nazwy. Dzięki.

3
Riddle napisał(a):

@obscurity: Czego nie rozumiesz, jak Ci mówię że ten wątek nie dotyczy w żadnym stopniu opinii o działaniu tej metody, a tylko i wyłącznie jej nazwy?

No ale to że założyłeś wątek to nie znaczy że możesz sobie w nim rozkazywać czy ustalać reguły. Forum dyskusyjne to miejsce w którym można prowadzić dyskusje, komentować, wymieniać się opiniami a także odpowiadać autorowi.
A odpowiadać w tym temacie w ogóle nie trzeba bo jest już ankieta w której zresztą zagłosowałem, więc w postach można sobie podyskutować obok tematu, niekoniecznie nawet z autorem wątku.

Riddle napisał(a):

Doceniam ciekawość forumowiczów nt tej funkcji, i fajnie że macie ochotę robić brainstorming nt tego jak mogłaby działać, ale to zostało już zrobione z zespołem, także dzięki. Teraz szukam tylko nazwy funkcji, także doceniłbym gdyby wszyscy zostali przy temacie nazwy. Dzięki.

Tu już ładniej napisałeś *głaszcze*

A w ogóle czemu pytasz o takie rzeczy losowych ludzi z internetu? Załóż dyskusję na githubie i spytaj swoich użytkowników którzy pewnie będą lepiej wiedzieli do czego to ma służyć i jak chcieliby żeby się to nazywało. A zrozumienie use-case'a funkcji jest kluczowe do jej nazwania bo to że funkcja ignoruje błędy to może (ale nie musi) być tylko szczegół implementacyjny. Tutaj nie dość że nikt nie używa tej bibliioteki to próba dopytania o szczegóły kończy się wylewaniem frustracji.

0
obscurity napisał(a):

A w ogóle czemu pytasz o takie rzeczy losowych ludzi z internetu? Załóż dyskusję na githubie i spytaj swoich użytkowników którzy pewnie będą lepiej wiedzieli do czego to ma służyć i jak chcieliby żeby się to nazywało.

To też zrobiłem. Po skończeniu tej ankiety porównam wyniki obu.

A zrozumienie use-case'a funkcji jest kluczowe do jej nazwania bo to że funkcja ignoruje błędy to może (ale nie musi) być tylko szczegół implementacyjny. Tutaj nie dość że nikt nie używa tej bibliioteki to próba dopytania o szczegóły kończy się wylewaniem frustracji.

Bardzo chętnie odpowiem na pytanie jak funkcja działa. Tylko spora część użytkowników tutaj nie pyta o to funkcja działa, tylko daje sugestie jak oni by ją zmienili.

Z resztą już nie będę odpowiadał na Twoje posty, przeczytaj sobie ten wątek cały od góry do dołu, i zobacz ile w nim jest faktycznych odpowiedzi z nazwą, albo pytania o to jak działa żeby lepiej dobrać nazwę (@dmw, @slsy, @yarel, @Hodor, @full_stock, @jvoytech), ale ile odpowiedzi próbuje wcisnąć swoją wizję (@Spearhead, @GodOfCode., @obscurity).

6

ile odpowiedzi próbuje wcisnąć swoją wizję (@Spearhead, @GodOfCode., @obscurity).

Nie mogę się zgodzić aby sugestię, dosłownie cytując, "można by rozważyć..." nazywać wciskaniem własnego rozwiązania.

Ogółem to problemem jest tu ton wypowiedzi. Przyzwoitość nakazuje być wdzięcznym za każdą wiadomość w wątku, bo oznacza ona, że ktoś poświęcił swój czas i energię by zapoznać się z cudzym problemem i dodać coś od siebie. Intencja jest dobra, nawet jeśli uwaga jest nietrafiona lub nie jest tym, czego szukasz. Reagowanie pokroju "nie pisz już w tym wątku" jest zwyczajnie słabe. Można te wiadomości zignorować (bez ostentacyjnego "nie będę już ci odpowiadał") albo spokojnie podziękować i stwierdzić, że to nie to czego szukasz zamiast być niepotrzebnie opryskliwym.

Doceniam ciekawość forumowiczów nt tej funkcji, i fajnie że macie ochotę robić brainstorming nt tego jak mogłaby działać, ale to zostało już zrobione z zespołem, także dzięki. Teraz szukam tylko nazwy funkcji, także doceniłbym gdyby wszyscy zostali przy temacie nazwy. Dzięki.

Taki komentarz jest jak najbardziej w porządku.

Dobra, daj już spokój. Widzę że nie jesteś w stanie skumać tego że ten wątek dotyczy tylko i wyłącznie nazwy funkcji. Dzięki za wkład w ten wątek, ale podziękuję już

Czego nie rozumiesz, jak Ci mówię że ten wątek nie dotyczy w żadnym stopniu opinii o działaniu tej metody, a tylko i wyłącznie jej nazwy?

Takie są raczej nie na miejscu.

1

Patrzysz na to z rzyci strony. Zamiast dodawać nową metodę i kombinować z nazwą, to stwórz flagę, która modyfikuje działanie:

$pattern = new Patter('[a-z]+', 'i');

// coś w ten deseń, może być to odpalane na `$pattern` może być na `$matcher`, jak będzie Ci pasowało
$matcher = $pattern->match('some string here')->ignoreErrors(true);

foreach ($matcher as $match) {

}

if (!$match->test()) {
  echo 'nothing found';
}
0
hauleth napisał(a):

Patrzysz na to z rzyci strony. Zamiast dodawać nową metodę i kombinować z nazwą, to stwórz flagę, która modyfikuje działanie:

$pattern = new Patter('[a-z]+', 'i');

// coś w ten deseń, może być to odpalane na `$pattern` może być na `$matcher`, jak będzie Ci pasowało
$matcher = $pattern->match('some string here')->ignoreErrors(true);

foreach ($matcher as $match) {

}

if (!$match->test()) {
  echo 'nothing found';
}

Tą flagę też trzeba jakoś nazwać, więc problem z nazwą pozostaje ten sam. Widzę że w Twoim przykładzie jest match + ignoreErrors, czyli przykład tożsamy z trzecią pozycją w ankiecie - możesz na niego zagłosować.

1 użytkowników online, w tym zalogowanych: 0, gości: 1