Wyrażenia regularne

0

Mając dowolną tablice Stringów np. {"abcde" , "bdace" , "ecdba" , "thg" , "htg" , "abc" } (jak widać są tutaj ciągi posiadające dokładnie te same znaki w tej samej ilości, ale w innej kolejności), potrzebuję takiego wyrażenia regularnego które dla dowolnego ciągu wejściowego, dopasowywałoby wyrażenia posiadające te same znaki w tej samej ilości, ale które ustawione są w ciągu w dowolnej kolejności np:

ciąg wejściowy "abcde" - dopasowania: "bdace" , "ecdba"
ciąg wejściowy "bdace" - dopasowania: "abcde" , "ecdba"
ciąg wejściowy "ecdba" - dopasowania: "abcde" , "bdace"
ciąg wejściowy "thg" - dopasowania: "htg"
itd..

Przez "ciąg wejściowy" rozumiem każdy kolejny elementy tablicy:

for(String s : tablica_stringow) {
    ...
}

Dla jasności, problem pojawił się, ponieważ dążę do uzyskania czegoś takiego:

{  "abcde" , "bdace" , "ecdba" , "thg" , "htg" ,  "abc"  }  -->  {  "3abcde" , "2ght"  ,  "abc"  }

Z góry dziękuje za każdą wskazówkę :)

2

^(?=[a-z]+$)(?!.*(.).*\1).*$ - https://regex101.com/r/PAjMCP/1 (załozyłem, że Twoje stringi są niepuste)
Zobacz na: https://www.regular-expressions.info/lookaround.html

EDIT Późna pora była i nie zauważyłem, o co Ci tak naprawdę chodzi:) Trzeba to zrobic inaczej (regexami też można, ale za każdym razem Musiałbyś zmieniać regexa, itd.): sprawdzać czy string z listy wejściowej jest permutacją stringa z danej tablicy stringów, po czym zaimplementować counter:

import java.util.HashMap;
import java.util.ArrayList;
import java.util.Arrays;

class Counter 
{
    public static String sort(String s) 
    { 
        char temp_array[] = s.toCharArray(); 
        Arrays.sort(temp_array); 
        return new String(temp_array); 
    } 
    
	static boolean isPermutation(String s1, String s2) 
	{	
		return sort(s1).equals(sort(s2));
	}
	
    public static HashMap<String, Integer> count (ArrayList<String> entry, ArrayList<String> targ) 
    {	
		HashMap<String, Integer> counter = new HashMap<>();
        for (String s : entry) 
        {
			for (String t : targ)
			{
				
				if (isPermutation(s, t))
				{
					if (counter.containsKey(s))
					{
						int val = counter.get(s);
						counter.put(s, val + 1);
					}
					else
					{
						counter.put(s, 1);
					}
				}
			}
		}
        return counter;
    }
    public static void main (String [] args) 
    {
		ArrayList<String> initial_list = new ArrayList<>(Arrays.asList("abcde", "ght", "abc"));
		ArrayList<String> target_list = new ArrayList<>(Arrays.asList( "abcde" , "bdace" , "ecdba" , "thg" , "htg" ,  "abc" ));
		
		System.out.println(count(initial_list, target_list)); // -> {ght=2, abc=1, abcde=3}
	}
}
2

imo regexy pasuja tu jak piesc do nosa.
czemu nie np tak (tj. pogrupuj po posortowanych stringach, sformatuj zeby ich liczba byla na poczatku, wyswietl), duzo trudniej tu sobie strzelic w stope, nie mowiac o prostocie i latwosci potencalnych modyfikacji:

Function<String, String> sort = s -> s.chars().sorted().collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append).toString();
Function<Map.Entry<String, List<String>>, String> format = kv -> kv.getValue().size() + kv.getKey();
Stream.of(tablica_stringow).collect(Collectors.groupingBy(sort)).entrySet().stream().map(format).forEach(System.out::println);
0

Dziękuje za odpowiedzi.
Żeby jak najbardziej przybliżyć o co mi chodzi, to staram się stworzyć klasę ułamków Fraction, w której można używać liter, zmiennych albo dowolnie dużych liczb tzn.

public class Fraction {

    public List<FractionPair> numerator;
    public List<FractionPair> denominator;
    private static ListList<FractionPair> tmp_list = new ArrayList<FractionPair>();

    public Fraction() {
        numerator = new ArrayList<FractionPair>();
        denominator = new ArrayList<FractionPair>();
    }
    private static void loop(List<FractionPair> L1, List<FractionPair> L2) {
        tmp_list.clear();
		
        for(FractionPair i : L1) {
            for(FractionPair j : L2) {
                tmp_list.add(i.mul(j));
            }
        }
    }
    public Fraction add(Fraction val) {
        Fraction result = new Fraction();
		
        loop(this.numerator, scnd.denominator);
        result.numerator = new ArrayList<FractionPair>(tmp_list);
		
        loop(scnd.numerator, this.denominator);
        result.numerator.addAll(tmp_list);
		
        loop(this.denominator, scnd.denominator);
        result.denominator = new ArrayList<FractionPair>(tmp_list);
        tmp_list.clear();
		
        result.simplify();
        return result;
    }
    private void simplify() {
    	TUTAJ POJAWIA SIĘ PROBLEM
    }
}

class FractionPair {
	
	public BigInteger  number_num;
	public String      number_str;
	
	public FractionPair() {
		
	}
	public FractionPair mul(FractionPair scnd) {
		FractionPair result = new FractionPair();
		
		result.number_num = this.number_num.multiply(scnd.number_num);
		result.number_str = this.number_str.concat("*" + scnd.number_str);
		
		return result;
	}
}

Zatem na przykład dane są dwa obiekty typu Fraction:

F1:
	numerator: { (12, "z_1") , (5, "b") }
	denominator: { (1, "c") , (-4, "d") }

F2:
	numerator: { (10, "ZM_2") , (7, "G") }
	denominator: { (1, "t") , (99, "A_2") }

F3 = F1.add(F2):
	numerator: { (12,"z_1*t"),(1188,"z_1*A_2"),(5,"b*t"),(495,"b*A_2"),(10,"ZM_2*c"),(-40,"ZM_2*d"),(7,"G*c"),(-28,"G*d") }
	denominator: { (1, "c*t") , (99, "c*A_2") , (-4, "d*t") , (-396, "d*A_2") } 

Taki wynik otrzymuję obecnie, gdzie nawias oznacza element listy: (number_num, number_str)

Na tym przykładzie tego oczywiście nie wyjaśnię, ale dla bardziej złożonych operacji pojawiają się dokładnie te same wyrazy, o ewentualnie innych współczynnikach liczbowych i chodzi o to, aby za pomocą funkcji simplify() jak najbardziej "zwinąć" ułamek, czyli to co się da dodać to dodać co się da skrócić to skrócić itd. np:

{ (10,"ZM_C*a*b") , (-8,"b*ZM_C*a") } --> { (2,"a*b*ZM_C") } lub { (2,"b*a*ZM_C") } lub { (2,"ZM_C*b*a") } itd. - kolejność wyrazów "zwiniętych" nie ma znaczenia

Mam nadzieję że jako tako wiadomo teraz o co mi chodziło.

PS.
Przepraszam ale w pierwszym poście zapomniałem dodać że ciągi wejściowe wyglądają tak jak podałem powyżej: "a*b*c*d_2" <-- litery, zmienne oddziela znak '*', aby sprawdzać gdzie zaczyna się lub kończy zmienna bądź litera.

1

Musisz w takim razie zdefiniować w Twoich Fraction odpowiednie działania aby zrobić z nich strukturę algebraiczną zwaną Euclidean Ring . Jest to najszersza struktura (należą do niej, np. wielomiany, czy tzw. Gaussian integers) w której można zdefiniować algorytm gcd (Greatest Common Divisor). A wtedy "zwinięcie" ułamaka staje się trywialne:
simplifiedFraction = (numerator / gcd(numerator, denominator), denumerator / gcd(numerator, denumerator) .

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