LINUX.ORG.RU

Разобрать строчку

 


0

1

Помогите с псевдокодом, есть строчка такого типа:211(1,2,5,8),212(9,14,36)

Т.е. в скобках может любое кол. Элементов, макс. двухзначных

Нужно разобрать ее в массив элементами 211_1, 211_2 … 212_36

Помогите, дайте денег на еду.


ChatGPT не против прокормить:

функция разобратьСтроку(строка):
    массивЭлементов = []
    началоЭлемента = 0
    
    для каждыйСимвол в строка:
        если каждыйСимвол является числом:
            продолжить
        
        если каждыйСимвол = "(":
            началоЭлемента = индексСледующегоСимвола(каждыйСимвол)
        
        если каждыйСимвол = "," или каждыйСимвол = ")":
            конецЭлемента = индексПредыдущегоСимвола(каждыйСимвол)
            элемент = строка[началоЭлемента:конецЭлемента]
            массивЭлементов.добавить(элемент)
            
            если каждыйСимвол = ")":
                выйти из цикла
        
    вернуть массивЭлементов

строка = "211(1,2,5,8),212(9,14,36)"
массив = разобратьСтроку(строка)
вывести массив

Естественно, какое описание, такое и решение, т.е. никакое.

vvn_black ★★★★★
()
Последнее исправление: vvn_black (всего исправлений: 1)

Быстро:

import re
input = '211(1,2,5,8),212(9,14,36)'
def govno_fix(matches):
  return ','.join(map(lambda x: matches[1] + '_' + x, matches[2].split(',')))

>>> print(re.sub(r'(\d+)\((.*?)\)', govno_fix, input))
211_1,211_2,211_5,211_8,212_9,212_14,212_36

Правильно: рекурсивный спуск [на лицо]

uwuwuu
()
proc enum {argument1 argument2} {
    if {$argument1 == ""} {
    return $argument2
    }
    if {$argument2 == ""} {
    return $argument1
    }
    return "$argument1, $argument2"
}
 
proc build_list {first args} {
    set output_string ""
    foreach p $args {
    set output_string [enum $output_string ${first}_${p}]
    }
    return $output_string
}
 
proc process_string {arg} {
    set args_list [regexp -inline -all {\d+\(\d+[,\d+]+\)} $arg]
    set output_result ""
    foreach p $args_list {
    set partial_list [build_list {*}[regexp -all -inline {\d+} $p]]
    set output_result [enum $output_result $partial_list]
    }
    return $output_result
}

И вот так работает:

eltclsh > process_string "211(1,2,5,8),212(9,14,36)"
211_1, 211_2, 211_5, 211_8, 212_9, 212_14, 212_36
czan
()
Ответ на: комментарий от uwuwuu

Зачем тут рекурсия? О_о Строгий формат, строгие сепараторы, три-четыре case для всего, один проход и результат готов. Если нужен пример, то лови:

uint stoi ( string s ) @trusted
{
    uint t = 0u;
    ubyte n, k = 0u;
    foreach( char ch; s )
    {
        if ( ch == '.' )
        { 
            t += n << ( 24u - ( 8u * k++ ) ); 
            n = 0u;
        }
        else
        {
            n = cast(ubyte)(( n * 10u ) + ch - 48u);
        }
    }
    return t += to!uint( n );
}

Тут тоже самое, только разбор ip. Смысл, думаю, понятен.

Anoxemian ★★★★★
()
Ответ на: комментарий от Anoxemian

И твой недоязык не идет ни в какое сравнение с божественными однострочниками на Jo-Es:

'127.0.0.1'.split('.').map((v, i) => parseInt(v) << (24 - i * 8)).reduce((a, b) => a + b)

Нельзя там ничего в один проход сделать. И регулярки всяко быстрее работают чем императивщина на скриптовых языках.

uwuwuu
()

Должно работать

defmodule Test do
  @string "211(1,2,5,8),212(9,14,36)"

  def run do
    acc = %{result: [], left: "", right: "", in?: false}

    @string
    |> String.split("")
    |> Enum.reduce(acc, fn
      "(", acc -> acc |> toggle_in()
      ")", acc -> acc |> push() |> clear() |> toggle_in()
      ",", acc -> if acc.in?, do: acc |> push() |> clear(:right), else: acc
      num, acc -> acc |> append(num)
    end)
    |> Access.get(:result)
  end

  defp push(acc) do
    entry = "#{acc.left}_#{acc.right}"

    acc.result
    |> update_in(&[entry | &1])
  end

  defp append(acc, num) do
    key = if acc.in?, do: :right, else: :left

    acc[key] |> update_in(&(&1 <> num))
  end

  defp clear(acc, dir), do: acc[dir] |> put_in("")

  defp clear(acc), do: acc |> clear(:left) |> clear(:right)

  defp toggle_in(acc), do: acc.in? |> update_in(&(!&1))
end

ddidwyll ★★★★
()
Последнее исправление: ddidwyll (всего исправлений: 4)

Всё просто.

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

char a[] = "211(1,2,5,8),212(9,14,36)";

int main()
{
    char * ptr = a;
    char * key = NULL;
    char * tab = "(,)";
    char * fmt = "%s_%s,\n";
    keys:{
        key=ptr;
        if(*key==' ' || *key=='\n'){
            key++;
            goto skip;
        }
        skip:{
            if(*key==' ' || *key=='\n'){
                key++;
                goto skip;
            }
        }

        if((ptr = strchr(ptr,tab[0]))){
            *ptr='\0';
             ptr++;
             (*ptr=='\0')?exit(0):0;
             goto values;
    }}

    values:{
        char * var = strchr(ptr,tab[1]);
        char * car = strchr(ptr,tab[2]);
        if(var && car){
        if(var <  car){
            *var=0;
            printf(fmt,key,ptr);
            ptr=++var;
            goto values;
        }else{
            *car=0;
             printf(fmt,key,ptr);
             car++;
             ptr=(strchr(car,tab[1]));
             (ptr)?ptr++:exit(0);
            goto keys;
        }}else if (!var){
             *car=0;
             printf(fmt,key,ptr);
             exit(0);
    }}
    return 0;
}
dron@gnu:~$ gcc lol.c && ./a.out 
211_1,
211_2,
211_5,
211_8,
212_9,
212_14,
212_36,
dron@gnu:~$
LINUX-ORG-RU ★★★★★
()
Ответ на: комментарий от LINUX-ORG-RU

Все равно питон лучший!

>>> class Parser:
...   ch = None
...   open_paren = 0
...   def __init__(self, stream):
...     self.stream=stream
...     self.stream.seek(0)
...   def advice(self):
...     self.ch = self.stream.read(1)
...     return self.ch
...   def eof(self):
...     return self.ch == ''
...   def number(self):
...     val = ''
...     while self.ch.isdigit():
...       val += self.ch
...       self.advice()
...     assert val
...     return val
...   def parse(self):
...     res = []
...     while self.advice() and not self.eof():
...       res.append(self.number())
...       if self.eof():
...         break
...       if self.ch == ',':
...         continue
...       if self.ch == '(':
...         self.open_paren += 1
...         last = res.pop()
...         res.extend(map(lambda x: last + '_' + x, self.parse()))
...         continue
...       if self.ch == ')' and self.open_paren:
...         self.open_paren -= 1
...         assert self.advice() == ',' or self.eof()
...         break
...       raise ValueError(f"unexpected: {self.ch!r}")
...     return res
... 
>>> import io
>>> stream=io.StringIO("211(1,2,5,8),212(9,14,36)")
>>> print(','.join(Parser(stream).parse()))
211_1,211_2,211_5,211_8,212_9,212_14,212_36
>>> 
uwuwuu
()
Ответ на: комментарий от bo4ok

оно вообще все регулярками с калбеками делается:

'211(1,2,5,8),212(9,14,36)'.replace(/([^,]+?)\((.+?)\)/g, (_, m0, m1) => m1.replace(/^|,/g, '$&' + m0 + '_'))
'211_1,211_2,211_5,211_8,212_9,212_14,212_36'

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

uwuwuu
()
Ответ на: комментарий от bo4ok

Тебе с состояниями, да? Типа, ну вот сейчас мы собираем префикс. Так, скобка, префикс собрали, пошли элементы. Запятая, ещё один элемент, закрывающая скопка - ща новый префикс будет. Так, штоле? Ах ты старый фортрановый извращенец, надо на тебя донести на всякий случай

DumLemming ★★
()
Ответ на: комментарий от superuser

и ты мне там что-то ставил на единственное правильное решение с рекурпсивным спуском [на лицо]

~
❯ eval echo $(echo '211(1,2,5,8),212,213(9,14,36)' | sed 's/(/_{/g; s/),/} /g; s/)/}/g') | sed 's/ /,/g'
211_1,211_2,211_5,211_8,212,213_9,212,213_14,212,213_36

то тестовое задание и автору подойдут решения на js, python либо php. а в них во всех есть калбеки при замене по регулярке

uwuwuu
()
Ответ на: комментарий от uwuwuu

тогда thebest3:

#!/bin/bash
P(){ R=$R$@; }
x="$@"
for (( i = 0; i < ${#x}; ++i)); do
C=${x:$i:1}
case "$C" in 
'(') P '_{'; k=1 ;;
')') P '}'; k= ;;
',') [ -n "$k" ] && P ',' || P ' ' ;;
*  ) P "$C" ;;
esac
done
eval echo $R
$ thebest3 '211(1,2,5,8),212,213(9,14,36)'
211_1 211_2 211_5 211_8 212 213_9 213_14 213_36

superuser ★★★★★
()
Ответ на: комментарий от Anoxemian

Для любителей без регулярок и в один проход:

proc enum {argument1 argument2} {
    if {$argument1 == ""} {
	return $argument2
    }
    if {$argument2 == ""} {
	return $argument1
    }
    return "$argument1, $argument2"
}

proc string_head {input_string} {
    return [string index $input_string 0]
}

proc string_tail {input_string} {
    return [string range $input_string 1 end]
}

proc process_inner_sequence {head_value accum_string accum_value input_string} {
    set first_char [string_head $input_string]
    switch $first_char {
	")" {return [process_outer_sequence "" [enum $accum_string ${head_value}_$accum_value] [string_tail $input_string]]}
	"," {return [process_inner_sequence $head_value [enum $accum_string ${head_value}_${accum_value}] "" [string_tail $input_string]]}
	default {return [process_inner_sequence $head_value $accum_string "${accum_value}${first_char}" [string_tail $input_string]]}
    }
}
	
proc process_inner_seq {head_value accum_string input_string} {
    return [process_inner_sequence $head_value $accum_string "" $input_string]
}

proc process_outer_sequence {head_value accum_string input_string} {
    set first_char [string_head $input_string]
    if {$input_string == ""} {return $accum_string}
    switch $first_char {
	"(" {return [process_inner_seq $head_value $accum_string [string_tail $input_string]]}
	"," {return [process_outer_sequence "" $accum_string [string_tail $input_string]]}
	default {return [process_outer_sequence ${head_value}${first_char} $accum_string [string_tail $input_string]]}
    }
}

proc process_sequence {input_string} {
    return [process_outer_sequence "" "" $input_string]
}

Результат:

puts [process_sequence "211(1,2,5,8),212(9,14,36)"]
211_1, 211_2, 211_5, 211_8, 212_9, 212_14, 212_36

Потыкать можно здесь.

Правда за O(1) эту задачу не решить.

czan
()

псевдокодом

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

$s = '211(1,2,5,8),212(9,14,36)';
preg_match_all('#(\d+)\((.*?)\)#', $s, $matches, PREG_SET_ORDER);

$result = [];

foreach ($matches as $match) {
    $items = explode(',', $match[2]);
    foreach ($items as $item) {
        $result[] = $match[1] . '_' . $item;
    }
}

emissar ★★
()

Вариант на вымирающем языке

#!/usr/bin/env perl
my $i='211(1,2,5,8),212(9,14,36)';

sub r {
  my $a = shift;
  return join(' ',map{$a.$_.',';} split /,/,$_[0]).' ';
}
$i =~ s/,?(\d+)\((.*?)\)/r($1.'_',$2)/ge;
print $i;
vel ★★★★★
()
Последнее исправление: vel (всего исправлений: 2)
Ответ на: комментарий от uwuwuu

и оно стало длинее портянки на яваскрипт

ужмите на сколько возможно пж
bashthebest:

#!/bin/bash
eval echo $(echo $@|sed 's/(/_\n{/g;s/)/}\n/g'|sed '/^[^{]/s/,/ /g;'|tr -d '\n')|sed 's/ /,/g'
$ bashthebest '211(1,2,5,8),212,213(9,14,36)'
211_1,211_2,211_5,211_8,212,213_9,213_14,213_36

superuser ★★★★★
()

Пытаясь вспомнить, всё, что я забыл:

lexer.l:

%{
#include <stdio.h>
#include "y.tab.h"
%}

%%
[0-9]+      { yylval = atoi(yytext); return NUMBER; }
"("         { return LBRAKET; }
")"         { return RBRAKET; }
","         { return COMA; }
[ \n\t\r]   {}

%%

int
yywrap(void){
	return 1;
}

parser.y:

// declarations
%{
#include <stdio.h>
#include <stdarg.h>

int yylex(void);
void yyerror(const char *, ...);
int i;
int n;
int numbers[100];
%}

%%
// rules
%token NUMBER LBRAKET RBRAKET COMA;

expression	: /* empty */
		| paris
		| expression COMA paris
		;

paris		: NUMBER LBRAKET list RBRAKET
		{
			for (i = 0; i < n; i++) {
				printf("%d_%d\n", $1, numbers[i]);
			}
		}
		;

list		: NUMBER
		{
			n = 0;
			numbers[n++] = $1;
		}
		| list COMA NUMBER
		{
			numbers[n++] = $3;
		}
		;

%%
#include "lex.yy.c"

int main() {
	yyparse();
	return 0;
}

void
yyerror(const char *s, ...)
{
	va_list ap;
	va_start(ap, s);
	vfprintf(stderr, s, ap);
	fprintf(stderr, "\n");
	va_end(ap);
}

Makefile:

prog: y.tab.c lex.yy.c
	$(CC) -o $@ $<

y.tab.c: parser.y
	$(YACC) -d $<

lex.yy.c: lexer.l
	$(LEX) $<

input.txt:

211(1,2,5,8),212(9,14,36)

И результат:

make && ./prog < input.txt
211_1
211_2
211_5
211_8
212_9
212_14
212_36
beastie ★★★★★
()
Последнее исправление: beastie (всего исправлений: 1)

Так, теперь продакшен код на VBA, который работает, который я сам наклепал, да он с костылями, да это спагетти, но он будет работать и приносить пользу в одном очень большом и известном предприятии, хоть и на мальньком его участке:

Public Sub mycompare()

Const max_source_string_size As Byte = 120

Dim source_string As String Dim i As Byte

Dim string_size As Byte

source_string = ActiveCell.Value

string_size = Len(source_string)

If string_size > max_source_string_size Then

MsgBox "oversize: " & max_source_string_size

Exit Sub

End If

Dim source_matrix(max_source_string_size) As String

For i = 1 To string_size

source_matrix(i - 1) = Mid(source_string, i, 1)

Next i

Dim source_matrix_digits(max_source_string_size) As String

Dim k As Byte

k = 0

For i = LBound(source_matrix) To UBound(source_matrix)

If IsNumeric(source_matrix(i)) = True Or source_matrix(i) = "(" Or source_matrix(i) = ")" Or source_matrix(i) = "," Then

    source_matrix_digits(k) = source_matrix(i)

    k = k + 1

End If

Next i

Dim output_matrix(max_source_string_size) As String

Dim j As Byte

Dim count As Byte

Dim tmpstringsubj As String

Dim tmpstringitem As String

Dim inside As Boolean

Dim currentsubj As String

inside = False

j = 0

count = 0

tmpstringsubj = ""

tmpstringitem = ""

currentsubj = ""

For i = LBound(source_matrix_digits) To UBound(source_matrix_digits)

    If source_matrix_digits(i) = "(" Then

        inside = True

        j = 0

        Do While source_matrix_digits(i) <> ")" And inside = True

            If IsNumeric(source_matrix_digits(i)) = True And source_matrix_digits(i) <> "," Then

                tmpstringitem = tmpstringitem + source_matrix_digits(i)

            End If

            If source_matrix_digits(i) = "," Or source_matrix_digits(i) = ")" Then

                output_matrix(count) = currentsubj + "_" + tmpstringitem

                tmpstringitem = ""

                MsgBox output_matrix(count)

                count = count + 1

            End If

            i = i + 1

        Loop

         m = m + 1

    End If

    If source_matrix_digits(i) = ")" Then

        output_matrix(count) = currentsubj + "_" + tmpstringitem

        MsgBox output_matrix(count)

        count = count + 1

        tmpstringitem = ""

        inside = False

        j = 0

    End If

    If IsNumeric(source_matrix_digits(i)) = True And inside = False Then

        tmpstringsubj = tmpstringsubj + source_matrix_digits(i)

        j = j + 1

    End If

    If j = 3 And inside = False Then

        currentsubj = tmpstringsubj

        tmpstringsubj = ""

        j = 0

    End If

Next i

End Sub

ddp1
() автор топика