Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.73/11: Рейтинг темы: голосов - 11, средняя оценка - 4.73
1 / 1 / 0
Регистрация: 04.02.2020
Сообщений: 16
1

Поиск и выполнение операции с текстом внутри тега

04.02.2020, 21:44. Показов 1915. Ответов 5
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте, нужна помощь.

Я написал класс, поиска тега и подготовку (по тегу) текста для записи в FollowDocument. Проблема в том, что метод вызывает сам себя для обработки теста из-за чего возникает исключение System.StackOverflowException. Как можно переписать метод, чтобы это исключение не появлялось?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
class ParseTextToXaml
        {
            private List<TagHandler> tags = new List<TagHandler>();
            private string doneText;
            private ParseTextToXaml parse;
 
            public string Parse(string s)
            {
 
                Parse(s, out List<string> parseText, '[', ']');
 
                return Parse(parseText, "[", "]");
 
            }
 
            private string Parse(List<string> s, string startBracket, string endBracket)
            {
                try
                {
                    int pos1 = -1;
                    for (int i = 0; i < s.Count; i++) //Ищет первый тег
                        if (s[i].Contains(startBracket) && s[i].Contains(endBracket))
                        {
                            pos1 = i;
                            break;
                        }
 
                    if (pos1 == -1) // Проверяет нахождение первого тега
                    {
                        string done = "";
                        for (int i = 0; i < s.Count; i++)
                            done += s[i];
                        doneText += ParseDoneText(done, tags);
                        return doneText;
                    }
 
                    string tagName = s[pos1]; // Вытаскивает тег
                    string tagVar = "";
                    tagName = tagName.Remove(0, 1);
                    tagName = tagName.Remove(tagName.Length - 1, 1);
 
                    if (tagName.Contains(" ")) // Разделение тега, если есть варианты
                    {
                        int posp = tagName.IndexOf(" ");
                        tagVar = tagName.Substring(posp + 1, tagName.Length - 1);
                        tagName = tagName.Substring(0, posp - 1);
                    }
 
                    string beforeTag = ""; 
 
                    for (int i = 0; i < pos1; i++)
                        beforeTag = s[i];
 
                    beforeTag = ParseDoneText(beforeTag, tags); // Подготовка текста для печати
 
                    tags.Add(new TagHandler { tagName = tagName, tagVar = tagVar });
 
                    int pos2 = -1;
 
                    for (int i = 0; i < s.Count; i++) // Поиск второго, закрывающегося тега
                        if (s[i] == $"[/{tagName}]")
                        {
                            pos2 = i;
                            break;
                        }
 
                    int pos3 = -1;
 
                    for (int i = pos2 - 1; i > pos1; i--) // Проверка, есть ли внутренние теги
                        if (s[i].Contains(startBracket) && s[i].Contains(endBracket))
                        {
                            pos3 = i;
                            break;
                        }
 
                    string beforeInTag = "";
 
                    List<string> newS = new List<string>();
 
                    if (pos3 != -1) // Если есть внутренние теги разделить так 
                    {
 
                        for (int i = pos3 + 1; i < pos2; i++)
                            beforeInTag = s[i];
 
                        parse = new ParseTextToXaml();
 
                        beforeInTag = ParseDoneText(beforeInTag, tags);
 
                        for (int i = pos1 + 1; i < pos2 - (pos2 - 1 - pos3); i++)
                            newS.Add(s[i]);
                    }
                    else // если нет так
                    {
 
                        for (int i = pos1 + 1; i < pos2; i++)
                            newS.Add(s[i]);
                    }
 
                    parse = new ParseTextToXaml();
 
                    string inTag = parse.Parse(newS, tags); // Подготовка текста внутри скобок 
 
                    List<string> afterTag = new List<string>();
 
                    for (int i = pos2 + 1; i < s.Count; i++)
                        afterTag.Add(s[i]);
 
                    parse = new ParseTextToXaml();
 
                    string aftertag = parse.Parse(afterTag, startBracket, endBracket); //
 
                    doneText += beforeTag + inTag + beforeInTag + aftertag;
                    return doneText;
                }
                catch (Exception e)
                {
                    return @"<Run>Ошибка: " + e + " </Run>";
                }
            }
            // Доп. метод для запуска
            private string Parse(List<string> s, List<TagHandler> tags)
            {
 
                this.tags = tags;
                return Parse(s, "[", "]");
 
            }
            // Подготовка текста к печати
            private string ParseDoneText(string s, List<TagHandler> tags)
            {
                if (s == "" || s == null)
                    return "";
 
                string run = @"<Run ";
 
                foreach (TagHandler el in tags)
                    switch (el.tagName)
                    {
                        case "b":
                            run += @"FontWeight='Bold' "; //в конце тега обязательно пробел
                            break;
                        case "Font": // Тестовый пробег по фонту, не готов
                            run += @"Font='text' ";
                            break;
                    }
 
                return run.Remove(run.Length - 1, 1) + @">" + s + @"</Run> ";
            }
            // Хранилище для тегов
            private struct TagHandler
            {
                public string tagName;
                public string tagVar;
            }
            // Разделяет предложенный текст на массив, с разделителями в виде тегов
            private void Parse(string s, out List<string> textParse, char startBracket, char endBracket)
            {
                textParse = new List<string>();
 
                for (int i = 0; i < s.Length; i++)
                {
                    int pos1 = s.IndexOf(startBracket);
                    int pos2 = s.IndexOf(endBracket);
 
                    if (pos1 == -1 && pos2 == -1)
                    {
                        textParse.Add(s);
 
                        return;
                    }
                    else if (pos1 == -1)
                    {
                        textParse.Add(s.Substring(0, pos2));
                        s = s.Substring(pos2 + 1, s.Length - pos2 - 1);
                        continue;
                    }
                    else if (pos2 == -1)
                    {
                        textParse.Add(s.Substring(0, pos1));
                        s = s.Substring(pos1 + 1, s.Length - pos1 - 1); 
                        continue;
                    }
                    else if (pos2 < pos1)
                    {
                        textParse.Add(s.Substring(0, pos2));
                        s = s.Substring(pos2 + 1, s.Length - pos2 - 1); 
                        continue;
                    }
 
                    string beforeTag = s.Substring(0, pos1); // выделяет все что находится до скобок
 
                    textParse.Add(beforeTag);
 
                    textParse.Add(s.Substring(pos1, pos2 - pos1 + 1)); //извлекает тег из скобок)
 
                    s = s.Substring(pos2 + 1, s.Length - pos2 - 1); // все что после скобок
                }
            }
        }
Добавлено через 17 минут
Забыл пометить:
Возникающая рекурсия замкнутая, она в любом случае заканчивается по достижению самого верхнего тега.
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
04.02.2020, 21:44
Ответы с готовыми решениями:

Поиск родительского тега, содержащего элемент с текстом
Добрый день, уважаемые форумчане! Есть таблица на странице такого вида: &lt;table...

ORA-14551: невозможно выполнение операции DML внутри запроса
Всем привет. Столкнулся с ошибкой ORA-14551: невозможно выполнение операции DML внутри запроса ...

Нужно сделать, чтобы значение атрибута тега отображался внутри этого тега
Как сделать чтобы html-код &lt;div class=&quot;item&quot;&gt;text&lt;/div&gt; отображался примерно вот так: del ...

Получение ссылки из тега внутри другого тега
Есть текст такого вида (пример): &lt;div class=&quot;group_row_labeled&quot;&gt;&lt;a...

5
Модератор
Эксперт .NET
15466 / 10712 / 2786
Регистрация: 21.04.2018
Сообщений: 31,532
Записей в блоге: 2
04.02.2020, 22:08 2
Цитата Сообщение от HZers Посмотреть сообщение
Я написал класс, поиска тега и подготовку (по тегу) текста для записи в FollowDocument. Проблема в том, что метод вызывает сам себя для обработки теста из-за чего возникает исключение System.StackOverflowException. Как можно переписать метод, чтобы это исключение не появлялось?
Код большой и немного путанный.
Полностью не разбирал.

Пару вопросов:

Какое отношение этот вопрос имеет к WPF? Наверное, вашу тему надо перенести в другой раздел.

Обратил внимание, что вы ищете открывающий тег, извлекаете его, ищете в нём вложенные и т.д.
Из-за этого возникают неоправданные рекурсии.
Не зная формата вашего документа, не могу точно сказать.
Но обычно типовой сценарий обработки скобок, тегов основан на поиске первой закрывающей скобки, тега.
Априори она принадлежит тегу самого нижнего уровня и при его обработке рекурсии не возникает.
После обработки этого тега ищется следующий закрывающий и при его обработке вложенный используется как уже сформированное значение. И т.д.
Такая обработка по закрывающим тегам, обычно позволяет значительно уменьшить или, вообще, избавиться от рекурсий.
0
1 / 1 / 0
Регистрация: 04.02.2020
Сообщений: 16
04.02.2020, 22:34  [ТС] 3
К WPF класс имеет косвенное отношение, так как просто составляет код для разметки, которая уже позже загружается отдельным методом в потоковый документ WPF.

Код путанный по причине, что я хоть и довольно сильно изучил C#, но все же не имею большого опыта.

После нахождения первого тега метод сначала записывает его в хранилище, а уже потом ищет следующий, первый закрывающийся тег такого же типа. После чего выделает ему нужные данные (вложенные теги) и отправляет выделенные данные на новую обработку, а новый обработчик уже сам отправляет и т.д. В общем это происходит пока он просто не сможет найти открывающийся тег и отправить все данные назад.
Если сказать проще здесь намеренная рекурсия, но увы, я не ожидал, что есть исключение связанное с этим.

Добавлено через 8 минут
А, да формат, класс принимает текст формата "Этот ["b"]текст["Font"] переводиться["/Font"].["/b"]" (без всех ковычек), получая на выходе что-то подобное:
XML
1
2
3
4
<Run>Этот</Run>
<Run FontWeight="Bold">текст</Run>
<RunFontWeight="Bold" Font="text">переводиться</Run>
<Run FontWeight="Bold">.</Run>
0
Модератор
Эксперт .NET
15466 / 10712 / 2786
Регистрация: 21.04.2018
Сообщений: 31,532
Записей в блоге: 2
04.02.2020, 23:05 4
Цитата Сообщение от HZers Посмотреть сообщение
К WPF класс имеет косвенное отношение, так как просто составляет код для разметки, которая уже позже загружается отдельным методом в потоковый документ WPF.
Код путанный по причине, что я хоть и довольно сильно изучил C#, но все же не имею большого опыта.
Я бы посоветовал разделить задачи работы с данными и их представлением.
WPF решает только задачу представления данных. И в этом разделе вам возможно придётся долго ждать помощи, если, вообще, её дождётесь.

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

Для решения же задачи по существу, в первую очередь, дайте пример ваших данных и требуемого их разбора.
Ни кто не будет по вашему коду заниматься воссозданием данных и алгоритма.
И код ваш скорее всего придётся выбросить.
Он даже для вас труден в чтении. Очень сомневаюсь, что кто-то станет его разбирать.
Его надо конкретно рефакторить - разбивать на методы.
Не должно методов с кодом больше одной страницы - одно из правил хорошего кода.
Добавьте хотя бы нормальные комменты к каждому участку кода.
0
1 / 1 / 0
Регистрация: 04.02.2020
Сообщений: 16
04.02.2020, 23:59  [ТС] 5
Хорошо, чуть позже я займусь разборкой кода, может смогу найти другой алгоритм, в котором отсутствует рекурсия.
Насчет переноса темы, увы, я новичок на форуме и не знаю как это здесь сделать, буду благодарен если отпишите как.

Добавлено через 23 минуты
Суть проблемы:

В первом сообщении представлен рабочий код, в ходе которого текст из такого формата:
"Этот ["b"]текст["Font"] переводиться["/Font"].["/b"]" (без всех ковычек)
Собирается в код разметки Xaml такого формата:
XML
1
2
3
4
<Run>Этот</Run>
<Run FontWeight="Bold">текст</Run>
<Run FontWeight="Bold" Font="text">переводиться</Run>
<Run FontWeight="Bold">.</Run>
Основная проблема заключается в том, что метод, проводящий обработку, в некоторых местах вызывает сам себя, для обработки какой-то части текста, в ходе чего образуется рекурсия.
При небольшом количестве тегов 2-3, исключение о рекурсии не возникает и код собирается правильно, но при большем количестве выскакивает исключение.
Как можно переписать метод, чтобы он не вызывал сам себя?

Добавлено через 18 минут
Алгоритм кода:

В открытый метод Parse передается строка, которая сразу разбивается на строковой массив (List), разделителями являются сами теги, которые так же записываются в этот массив.
После, массив передается в другой, приватный, метод Parse который обрабатывает текст:
1. Ищет первый попавшийся ему тег;
2. Проверяет, точно ли был тег найден, если нет собирает текст в нужный формат с учетом тегов уже записанных в хранилище tags и возвращает значение;
3. Избавляется от скобок в теге и разбивает на варианты, если присутствуют, добавляет тег в хранилище tags;
4. Собирает текст, находящийся до тега в нужный формат;
5. Ищет второй закрывающийся тег;
6. Смотрит, находятся ли вложенные теги, если да то вытаскивает текст между закрывающими тегом и последним найденным вложенным тегом и собирает в нужный формат. Если вложенных тегов не имеется собирает весь текст между текущими тегами в формат;
7. Отправляет вложенные теги в новый обработчик, при этом передавая уже существующие теги;
8. Отправляет в новый обработчик текст после текущих тегов;
9. Собирает код и возвращает его;
0
1 / 1 / 0
Регистрация: 04.02.2020
Сообщений: 16
05.02.2020, 14:29  [ТС] 6
Сам нашел решение проблемы, полностью избавился от всех рекурсий.
Если кому понадобиться оставляю переписанный класс:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
class ParseTextToXaml
        {
            /// <summary>
            /// Преобразует текст из формата "При[Font size=3 family=Font_A]вет [/b]мир[/b][/Font]!"
            /// в формат пригодный для записи в потоковые документы (пока без погаргафов). 
            /// Для обозначения пробелов в нутри значения тега использовать _
            /// </summary>
            /// <param name="s">Строка для сборки</param>
            public static string Parse(string s)
            {
                // Задание значений для открывающегося и закрывающегося тега
                string startBracket = "[";
                string endBracket = "]";
 
                string doneText = "";
 
                List<string> textParce = SplitText(s, startBracket, endBracket); // Резделение текста
                foreach (string el in textParce)
                    Console.WriteLine(el);
 
                doneText += TwoTagsParse(textParce, startBracket, endBracket); // Преобразование в код Xaml на основе твух тегов
 
                return doneText;
            }
 
            /// <summary>
            /// Производит подготовительный сбор текста (создает Run), учитывая теги.
            /// </summary>
            /// <param name="s">Строковой массив содержащий иески вместе с тегами.</param>
            /// <param name="startBracket">Открывающаяся скобка тега.</param>
            /// <param name="endBracket">Закрывающаяся скобка тега.</param>
            /// <returns>Возвращает текст записанный в Run.</returns>
            private static string TwoTagsParse(List<string> s, string startBracket, string endBracket)
            {
                // Произвоиться запись тега вместе с текстом, для последующего преобразования. Текст записывается по порядку следования
                List<TextHandler> textHandler = new List<TextHandler>();
 
                // Записываются все найденные открытые теги по пути, если найден закрывающийся тег такогоже типа, то открытый тег закрывается
                List<TagHandler> openTags = new List<TagHandler>();
 
                for (int i = 0; i < s.Count; i++)
                {
                    try
                    {
                        for (int j = 0; j < openTags.Count; j++)
                            if (openTags[j].tagEnd == i)
                                openTags.RemoveAt(j);
 
                        // Проверка на закрывающийся тег
                        if (s[i].Contains("/"))
                            continue;
 
                        int pos1 = -1;
                        // Смотрит содержит ли предоставленный элемент текста открывающийся текст
                        if (s[i].Contains(startBracket) && s[i].Contains(endBracket))
                            pos1 = i;
                        else // Если не содержит, то текст записывается в держатель вместе со всеми открытыми тегами
                        {
                            TextHandler tempTextHandler = new TextHandler();
                            tempTextHandler.text = s[i];
                            foreach (TagHandler el in openTags)
                                tempTextHandler.tags.Add(el);
 
                            textHandler.Add(tempTextHandler);
 
                            continue;
                        }
 
                        // Резделение тега и его вариантов, раделителями являются пробелы, лишние пробелы в начале не допустимы
                        string tagName = s[pos1];
                        string tagVar = "";
                        tagName = tagName.Remove(0, startBracket.Length);
                        tagName = tagName.Remove(tagName.Length - endBracket.Length, endBracket.Length);
 
                        // Проверка на нахождение вариантов
                        if (tagName.Contains(" "))
                        {
                            int posp = tagName.IndexOf(" ");
                            tagVar = tagName.Substring(posp + 1, tagName.Length - posp - 1);
                            tagName = tagName.Substring(0, posp);
                        }
 
                        int pos2 = -1;
 
                        // Поиск закрывающегося тега
                        for (int j = pos1; j < s.Count; j++)
                            if ($"{startBracket}/{tagName}{endBracket}" == s[j])
                            {
                                pos2 = j;
                                break;
                            }
 
                        // Реагирование на не нахождение закрывающегося тега
                        if (pos2 == -1)
                            return @"<Run>Ошибка: Не найден закрывающийся тег для: " + startBracket + tagName + " " + tagVar + endBracket + " </Run>";
 
                        // Добавление тега в хранилище для последующей передачи
                        openTags.Add(new TagHandler { tagName = tagName, tagVar = tagVar, tagEnd = pos2 });
                    }
                    catch (Exception e) { return @"<Run>Ошибка: " + e + " </Run>"; }
                }
 
                string doneText = "";
                // Сборка текста
                foreach (TextHandler el in textHandler)
                    @doneText += @el.Parse();
 
                return @doneText;
            }
 
            /// <summary>
            /// Разделеяет предложенный текст на массив. Разделителями являются скобки тегов.
            /// </summary>
            /// <param name="s">Текст для разделения.</param>
            /// <param name="startBracket">Открывающаяся скобка тега.</param>
            /// <param name="endBracket">Закрывающаяся скобка тега.</param>
            /// <returns>Возвращает строкой массив с разделенными тегами и текстом.</returns>
            private static List<string> SplitText(string @s, string startBracket, string endBracket)
            {
                List<string> textParse = new List<string>();
                try
                {
                    for (int i = 0; i < s.Length + 30; i++)
                    {
                        // Поиск первого тега
                        int pos1 = s.IndexOf(startBracket);
                        int pos2 = s.IndexOf(endBracket);
 
                        if (pos1 == -1 && pos2 == -1) // Если в исходном тексте отсутствуют теги, вернуть готовый
                        {
                            @textParse.Add(@s);
 
                            return @textParse;
                        }
                        else if (pos1 == -1)
                        {
                            textParse.Add(s.Substring(0, pos2));
                            @s = @s.Substring(pos2 + 1, s.Length - pos2 - 1);
                            continue;
                        }
                        else if (pos2 == -1)
                        {
                            textParse.Add(s.Substring(0, pos1));
                            @s = @s.Substring(pos1 + 1, s.Length - pos1 - 1);
                            continue;
                        }
                        else if (pos2 < pos1)
                        {
                            textParse.Add(s.Substring(0, pos2));
                            @s = @s.Substring(pos2 + 1, s.Length - pos2 - 1);
                            continue;
                        }
 
                        string @beforeTag = @s.Substring(0, pos1); // Dыделяет все что находится до скобок
 
                        @textParse.Add(beforeTag);
 
                        @textParse.Add(s.Substring(pos1, pos2 - pos1 + 1)); // Извлекает тег
 
                        @s = s.Substring(pos2 + 1, s.Length - pos2 - 1); // Обновляет исходный текст, удаляя уже использованное 
                    }
                }
                catch (Exception e) { return new List<string> { "Ошибка: " + e + " " }; }
 
                return textParse;
            }
        }
 
        // Структура выполняющая хранение тега и текста готорый в ней находиться
        public class TextHandler
        {
            public List<TagHandler> tags = new List<TagHandler>();
 
            public string text;
 
            /// <summary>
            /// Метод собирает текст на осневе данных, которые ему уже были предоставлены.
            /// </summary>
            /// <returns>Возвращаяет уже собранный текст.</returns>
            public string Parse()
            {
                if (text == "" || text == null) // Проверка на то, что предоставленный текст не пустой
                    return "";
                try
                {
                    string run = @"<Run ";
 
                    foreach (TagHandler el in tags) // Запуск поиска просмотра тегов
                    {
                        string[] tagVar = new string[0];
 
                        if (el.tagVar != "" && el.tagVar != null) // Разделение всех вариантов тегов
                            tagVar = el.tagVar.Split(new char[] { ' ' });
 
                        switch (el.tagName)
                        {
                            case "b": // Жирный текст
                                run += @"FontWeight='Bold' ";
                                break;
                            case "Font": // Все, что связанно со шрифтами
                                foreach (string var in tagVar)
                                {
                                    string[] count = var.Split((new char[] { '=' }));
 
                                    if (count.Length >= 2) // Если в значении тега есть мнимые пробелы заменить их
                                        count[1] = count[1].Replace("_", " ");
 
                                    switch (count[0])
                                    {
                                        case "size":
                                            @run += @"FontSize='" + @count[1] + "' "; // Размер
                                            break;
                                        case "family":
                                            @run += @"FontFamily='" + @count[1] + "' "; // Шрифт
                                            break;
                                    }
                                }
                                break;
                        }
                    }
 
                    return @run.Remove(run.Length - 1, 1) + @">" + text + @"</Run> ";
                }
                catch (Exception e) { return @"<Run>Ошибка! Совет проверьте правельность написания тегов. " + e + @" </Run>"; }
            }
        }
 
        // Хранит в себе имя тега и все его варианты, если они присутствуют
        public struct TagHandler
        {
            public string tagName;
            public string tagVar;
            public int tagEnd;
        }
1
05.02.2020, 14:29
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
05.02.2020, 14:29
Помогаю со студенческими работами здесь

Скрипт идентификации тега внутри другого тега
Всем привет! Помогити пожалуйста. Есть такая структура &lt;span class=&quot;sub-item&quot; &gt; &lt;a...

"невозможно выполнение операции DML внутри запроса"
Добрый вечер! Обращаюсь к более опытным товарищам со следующей проблемой: Передо мной стояла...

Как сделать заголовок просто текстом, без тега h2?
имеется сайт http://rica-stom.ru/...olosti-rta.html с конкретной страницей хочу чтобы в материале...

Теги внутри тега a
Всех приветствую. Можно ли размещать внутри тега &lt;a&gt; другие элементы (например, теги &lt;div&gt; и &lt;p&gt;),...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru