Eu compilei uma lista de materiais que eu precisava em um jogo, começando de cima para baixo até seus ingredientes mais primitivos. No entanto, agora estou procurando uma maneira de calcular rapidamente os números.
21 reinforced alloy
21 damascus steel
21 steel
21 iron dust
21 carbon
21 iron
21 iron dust
21 carbon
21 iron
21 hardened metal
21 damascus steel
21 steel
21 iron dust
21 carbon
21 iron
21 iron dust
21 carbon
21 iron
21 duralmin
21 aluminum dust
21 copper dust
21 aluminum
21 aluminum dust
21 compressed carbon
84 carbon
21 aluminum bronze
21 aluminum dust
21 bronze
21 copper dust
21 tin dust
21 copper
21 aluminum
21 aluminum dust
21 corinthian bronze
21 silver dust
21 gold dust
21 copper dust
21 bronze
21 copper dust
21 tin dust
21 copper
21 solder
21 lead dust
21 tin dust
21 lead
21 lead dust
21 billon
21 silver dust
21 copper dust
21 silver
21 silver dust
21 gold 24 carat
Os níveis superiores não importam, pois estou procurando as matérias-primas que preciso coletar. Por exemplo, 21 hardened metal
e 21 damascus steel
não importa, porque estou procurando o total de 42 damascus steel
, o que também não importa, porque estou procurando 42 iron dust
, 42 carbon
, e 42 iron
(este exemplo não conta o restante da lista), o contagem total de matérias-primas.
Até agora, fiz isso em um site de teste regex , mas eventualmente gostaria de poder usar grep
para não ter que abrir um site para fazer a contagem. Eu gostaria de obter algo como "existem 5 ocorrências de carbono, aqui estão as linhas correspondentes" para que eu possa calcular mais facilmente, pois se eu souber que existem 5 ocorrências de carbono com 4 delas sendo e 1 sendo , 21 carbon
agora 84 carbon
posso calcular facilmente que eu preciso de um total de 21*4 + 84 = 168 carbon
.
Estou tentando contar as linhas que não têm outra linha com uma quantidade maior de guias a seguir, pois presumivelmente, se tiver, não é a matéria-prima.
/(\t+)\d+ aluminum\n(?!\1)/g
(substituindo "alumínio" por qualquer contagem de matéria-prima que estou tentando encontrar)
Isso não está encontrando nada embora. Existe uma maneira de conseguir o que estou tentando alcançar com o regex? Em caso afirmativo, como?
Obrigado pelo seu tempo.
Não tenho certeza se devo colocar isso no SO ou neste SE, mas como eventualmente quero poder usar, grep
pensei que este poderia ser o local mais apropriado.
Se você quiser usar regexps semelhantes ao perl, por que não usar o real:
Que dá:
-0777 -n
significa que toda a entrada é sugada para$_
. Om
sinalizador ultiline para om{...}
operador faz com que^
e$
corresponda no início e no final de cada linha$_
em vez de apenas no início e no final de$_
. Sem os
sinalizador,.
não corresponde a um caractere de nova linha, mas cuidado com o\s
que pode prejudicar as coisas aqui se houver linhas em branco na entrada.\s*+
é a versão sem retrocesso do\s*
. Não é estritamente necessário aqui, pois o que segue (\d+
) não pode corresponder a um espaço em branco.Standard
grep
não oferece suporte a regexps semelhantes a perl, como aqueles\d
e(?!\1)
operadores perl RE que você está usando, mas você pode usarpcregrep
o que também oferece suporte-o
a um modo multilinha com-M
:Você ainda precisaria canalizar para outra coisa como
perl
ouawk
fazer as somas, então isso tem pouca vantagem sobre usarperl
para tudo.Se o recuo pode ter uma mistura de tabulações e espaços, você pode querer que a entrada passe por um
expand
ouunexpand
primeiro para consolidá-los em apenas espaços ou apenas tabulações. Por padrão, eles consideram as paradas de tabulação com 8 colunas de distância, como a maioria dos terminais ou navegadores (mas não o stackexchange, que irritantemente tem 4 colunas de distância), mas veja a-t
opção de mudar isso.Uma linha é um "ingrediente primitivo" (primi) se seu nível for <= nível do próximo elemento. Isso é equivalente a:
A linha anterior é um primi se seu nível for <= nível atual (ou se for o último)
Usando awk com separador de campo "\t", os níveis são
NF
, os ingredientes são o último campo$NF
:Para resumi-los, você poderia executar algo ao longo das linhas de
Você precisa usar lookbehind e lookahead. Você também precisa tratar toda a entrada em conjunto, em vez de linha por linha. O seguinte comando deve fazer o que você deseja:
-P
ativa a sintaxe Perl.-z
usa terminador nulo, em vez de novas linhas.-o
emite apenas a correspondência.(?<=\n)
olha para trás para uma nova linha. Isso está no lugar de^
, que normalmente corresponderia ao início de cada linha. Para olhar negativo para trás, use(?<!...)
. Estou ignorando a primeira linha porque presumivelmente sempre haverá um nível mais profundo. Se não for esse o caso, você pode adicionar uma nova linha ao início da entrada antes de enviá-la paragrep
. Provavelmente existem maneiras melhores de fazer isso, mas aqui está uma:(\s+)
captura o nível de indentação. Isto é referido mais tarde como\1
.\s
corresponde ao espaço em branco. Um problema potencial com isso é que as novas linhas podem ser consideradas parte do recuo. Por exemplo, novas linhas duplas são freqüentemente usadas como separadores de parágrafo. Você pode substituir\s
pelo espaço em branco específico que espera ser usado para recuo,[\ \t]
.(\S[^\n]*)
captura o texto de interesse.\S
corresponde a não-espaço em branco.[^\n]
corresponde a qualquer coisa que não seja uma nova linha.(?!\n\1\s)
olhar negativo para a frente para garantir que a próxima linha não seja recuada mais profundamente do que a linha atual. Para uma visão positiva do futuro, use(?=...)
.