Все технические форумы на одном сайте Удобный поиск информации с популярных форумов в одном месте
Вопрос: JsonValue из строки

Нужно получить JsonValue (JSR-374) из строкового представления JSON. Ожидал, что есть простой способ (например, предназначенный для этого статический метод). Но, перерыв кучу интернета, так и не нашёл ничего, кроме многошагового способа c привлечением средств ввода-вывода:

import java.io.StringReader;
import javax.json.Json;
import javax.json.JsonReader;
import javax.json.JsonValue;
...
JsonReader reader = Json.createReader(new StringReader( inputJsonString ));
JsonValue json = reader.readValue();
reader.close();


Неужели и правда в API не включили простого конвертера из строки в Json?
Ответ: В spring-boot так можно получить значение строки.

            org.springframework.boot.json.JsonParser springParser =
                org.springframework.boot.json.JsonParserFactory.getJsonParser();
            Map<String, Object> object = springParser.parseMap(jsonString);
            String birthday = String.valueOf(object.get("birthday"));


С уважением, Валентин
Вопрос: JsonValue и отсутствие тега

достаю значения большого количества тегов из JSON
street := JSONObject.Get('street_name').JsonValue.Value;

Проблема в том, что если будет отсутствовать тег "street_name", то вываливается AV.
Неудобство в том, что тегов весьма много и городить огород с проверками - получается огромный плохо читабельный код.
Может быть есть какое-то свойство/метод, которые могут выдать просто пустую строку?

или каждый раз надо проверять?
if Assigned(JSONObject.GET('street_name')) then



ну или свой лисапет?
Function GetJSONValAsString(const tag_name: string; JSONObject: TJSONObject): string;
Var
  JSONPair: TJSONPair;
begin
  JSONPair := JSONObject.Get(tag_name);
  if assigned(JSONPair) then
    result := JSONPair.JsonValue.Value
  else
    result := '';
Ответ:
X11
Я использую встроенную библиотеку пусть не очень активно и обширно, но пока серьёзных проблем нет.
Скорость не тестировал, не сравнивал, но на данный момент она мне не нужна.

С superobject код компактнее, скорость выше, работает в т.ч. и в восьмибитных неюникодных дельфях.
А еще SO умеет искать свойства по его имени. :)
Вопрос: Строка: две переменные типа string сравнить и вывести на экран кол-во ошибок

есть две переменные типа string нужно их сравнить и вывести на экран кол-во ошибок, то есть
Delphi
1
2
3
4
s1:='Тысяча';
s2:='fgghrty';
 
writeln('Кол-во ошибок - 6');
Ломаю голову как реализовать.. Знаю, что строка это массив символов(букв), но к нормальному решению так и не пришёл почти за 3 дня.
Ответ: Код программы:
Delphi
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
program Project2;
 
{$APPTYPE CONSOLE}
 
uses
  SysUtils;
var
//Строка без ошибок и строка с ошибками.
s1,s2:string;
//Длина строки без ошибок, длина строки с ошибками, общая длина, индекс, количество ошибок.
l1,l2,l,i,e:integer;
begin
//Вывод сообщения для ввода строки без ошибок.
        write('Введите строку без ошибок: ');
//Ввод строки без ошибок.
        readln(s1);
//Вывод сообщения для ввода строки с ошибками.
        write('Введите строку с ошибками: ');
//Ввод строки с ошибками.
        readln(s2);
//Получаем длину строки без ошибок.
        l1:=length(s1);
//Получаем длину строки с ошибками.
        l2:=length(s2);
//Если длина строки без ошибок больше длины строки с ошибками,
//то количество ошибок равно количеству пропущенных символов в строке с ошибками
//и общая длина равна длине строки с ошибками.
        if l1>l2 then
        begin
        e:=l1-l2;
        l:=l2;
        end
//Инаяе если длина строки с ошибками больше длины строки без ошибок,
//то количество ошибок равно количеству лишних символов с втроке с ошибками
//и общая длина равна длине строки без ошибок.
        else if l2>l1 then
        begin
        e:=l2-l1;
        l:=l1;
        end
//Иначе если строки равны,
//количество ошибок равно 0
//и общая длина равна одной из длин строк.
        else
        begin
        e:=0;
        l:=l1;
        end;
//Индекс символа меняется с 1 до общей длины.
        for i:=1 to l do
//Если символ по индексу строки без ошибок не равен символу строки с ошибками,
//то количество ошибок увеличивается на 1.
        if s1[i]<>s2[i] then
        e:=e+1;
//Вывод клоичества ошибок.
        writeln('Количество ошибок: ',e);
//Вввод ENTER.
        readln;
end.
Delphi выводит вместо русских символов абракадабру, поэтому можно записать на английском языке:
Delphi
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
program Project2;
 
{$APPTYPE CONSOLE}
 
uses
  SysUtils;
var
//Строка без ошибок и строка с ошибками.
s1,s2:string;
//Длина строки без ошибок, длина строки с ошибками, общая длина, индекс, количество ошибок.
l1,l2,l,i,e:integer;
begin
//Вывод сообщения для ввода строки без ошибок.
        write('Enter string without errors: ');
//Ввод строки без ошибок.
        readln(s1);
//Вывод сообщения для ввода строки с ошибками.
        write('Enter string with errors: ');
//Ввод строки с ошибками.
        readln(s2);
//Получаем длину строки без ошибок.
        l1:=length(s1);
//Получаем длину строки с ошибками.
        l2:=length(s2);
//Если длина строки без ошибок больше длины строки с ошибками,
//то количество ошибок равно количеству пропущенных символов в строке с ошибками
//и общая длина равна длине строки с ошибками.
        if l1>l2 then
        begin
        e:=l1-l2;
        l:=l2;
        end
//Инаяе если длина строки с ошибками больше длины строки без ошибок,
//то количество ошибок равно количеству лишних символов с втроке с ошибками
//и общая длина равна длине строки без ошибок.
        else if l2>l1 then
        begin
        e:=l2-l1;
        l:=l1;
        end
//Иначе если строки равны,
//количество ошибок равно 0
//и общая длина равна одной из длин строк.
        else
        begin
        e:=0;
        l:=l1;
        end;
//Индекс символа меняется с 1 до общей длины.
        for i:=1 to l do
//Если символ по индексу строки без ошибок не равен символу строки с ошибками,
//то количество ошибок увеличивается на 1.
        if s1[i]<>s2[i] then
        e:=e+1;
//Вывод клоичества ошибок.
        writeln('Number of errors: ',e);
//Вввод ENTER.
        readln;
end.
Вопрос: Разбить заданную строку на две части

добрый день
нужна программа, содержащая в себе подпрограмму, которая разбивает заданную строку на две части: первое слов (до первого пробела) и остальная часть строки (пробелы в начале строки убираются)
после выполнения программы все слова выводятся в консоль по отдельности
надыбал код не помню на каком сайте. проверил - работает. стал вникать в принципы ее реализации.. ии... всё )) ничего не понял

может кто-то намекнуть на правильные ответы для возникших вопросов?)
ASM
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
.186                                                ;чтобы можно было использовать push <число>
assume cs:code, ds:data, es:data
SSEG segment stack                 ;сегмент стека  
db 400h dup (?)
SSEG ends
code segment para public 'code'
start:
 mov ax, data
 mov ds, ax
 mov es, ax                                         ;пусть es=ds=data     
 
 lea dx, sString
 mov ah, 9
 int 21h                                            ;ждем строку
 
 mov bMax, 80                                       ;задаем максимальное значение строки (в нулевом будет 80 - макс длина)
 lea dx, bMax                                       ;в первом после ввода останется фактич длина, а со второй идут данные
 mov ah, 0ah
 int 21h                                            ;вводим строку
 
 lea dx, sResult
 mov ah, 9
 int 21h                                            ;выводим заголовок о выводе слов
 
 mov wAddr, offset bString                          ;адрес строки
next:
 push offset wAddr                                  ;адрес адреса строки
 call FirstWord                                     ;разбиваем на подстроки
 
 test ax, ax                                        ;ax = адресу слова, =0 - одни пробелы
 jz finish                                          ;в конце пробелы - на выход
 mov dx, ax
 mov ah, 9
 int 21h                                            ;выведем слово
 
 mov ah, 2                                          ;на новую строку
 mov dl, 0dh
 int 21h
 mov dl, 0ah
 int 21h
 cmp wAddr, 0                                       ;последнее слово?
 jne next                                           ;продолжаем разбивать строку
finish:
 lea dx, sPress
 mov ah, 9
 int 21h                                            ;press any key
 
 mov ah, 8
 int 21h                                            ;ждем any key
 
 mov ax, 4c00h
 int 21h  ;bye
 
                                                   ;Разбор строки на первое слово и все остальное
                                                   ;Исходная строка портится! В конце слова ставится $ для вывода по 9 функции
                                                   ;Параметр - адрес слова с адресом строки
                                                   ;Возвращается в ax адрес первого слова, в слове с адресом строки 
                                                   ; возвращается адрес подстроки, начинающейся за первым словом или 0 для последнего слова
ppStr equ [bp+4]                                   ;адрес адреса строки
FirstWord proc
 push bp
 mov bp, sp
 xor cx, cx                                        ;адрес первого слова
 mov bx, ppStr                                     ;адрес адреса строки
 mov si, [bx]                                      ;адрес строки
SearchBegin:                                       ;цикл разбора строки
 lodsb                                             ;очередной символ
 cmp al, 0dh                                       ;конец строки
 je FW_last                                        ;строка из одних пробелов
 cmp al, ' '                                       ;пробел?
 je SearchBegin                                    ;первые пробелы обходим
 lea cx, [si-1]                                    ;адрес начала слова
SearchEnd:                                         ;ищем конец слова
 lodsb                                             ;очередной символ
 cmp al, 0dh                                       ;конец строки
 je FW_last                                        ;последнее слово
 cmp al, ' '                                       ;конец слова?
 jne SearchEnd                                     ;ищем пробел после слова
 mov byte ptr [si-1], '$'                          ;поставим вместо пробела '$' для вывода
 jmp FW_ret                                        ;на выход
FW_last:                                           ;последнее слово или одни пробелы
 mov byte ptr [si-1], '$'                          ;поставим вместо пробела '$' для вывода
 xor si, si                                        ;больше слов нет
FW_ret:
 mov [bx], si                                      ;сохраним адрес второй подстроки или 0, если больше слов нет
 mov ax, cx                                        ;возвращаем адрес первого слова для вывода
 pop bp
 ret 2                                             ;уберем из стека параметр
FirstWord endp
code ends
 
data segment para public 'data'
sString db 0ah,'Enter string: $'
sResult db 0ah,0ah,'Words:',0dh,0ah,'$'
sPress db 0dh,0ah,'Press any key$'
                                              ;буфер для ввода числовой строки (для функции 0ah)
bMax db ?                                     ;максимальный размер буфера
bCount db ?                                   ;реальный размер строки
bString db 80 dup (?)                         ;сама строка
wAddr dw ?                                    ;адрес анализируемой строки
data ends
 
 end start
какой механизм использован в 16-17 строках?
мы вносим в bMax максимальное значение строки, а после туда же пишем строку, которую нам необходимо в будущем анализировать?
если так, то как мы получаем доступ к этой строке в процедуре, если название bMax после нигде не используется.
я, конечно, читал о структуре буфера. первый байт - максимальная длина строки, второй - фактическая, а с третьего идет сами данные.. как-то это взаимосвязано?)
Ответ: rostovskii_jeko,
В природе существует 5 команд, облегчающих манипуляции со строкам:
Кликните здесь для просмотра всего текста
Code
1
2
3
4
5
   STOSB  - запись из AL в DI;
   LODSB  - чтение в AL из SI;
   MOVSB  - копирование из SI в DI;
   CMPSB  - сравнивает байт DI, с байтом SI (сравнивает строки);
   SCASB  - сравнивает байт AL, с байтом DI (поиск символа в строке).

Для организации циклов применяется префикс REP с счётчиком CX, который при каждом цикле уменьшается на 1. При выполнении команд CMPSB/SCASB можно манипулировать флагами так, чтобы операция могла прекратиться сразу после обнаружения необходимого условия. Ниже - модификации префикса REP для этих целей.
REP применяется для STOSB/LODSB/MOVSB, а REPE - для CMPSB/SCASB:
Кликните здесь для просмотра всего текста
Code
1
2
3
   REP         -   продолжать, пока CX > 0;
   REPE/REPZ   -   прекратить, при не совпадении (сравнение строк);
   REPNE/REPNZ -   прекратить, при совпадении (поиск символа в строке).


Сообщение от rostovskii_jeko
нужна программа, которая разбивает заданную строку на две части:
- первое слов (до первого пробела);
- остальная часть строки (пробелы в начале строки убираются);
- все слова выводятся в консоль по отдельности
Я так понял, что нужно просто вывести все слова с новой строки..
Подпрограмма будет копировать отдельные слова (без пробелов) из источника(SI) в буфер-приёмник(DI).
Основная-же программа будет просто выводить с новой строки данные из приёмника функцией(9), которая требует маркер конца строки($). Перед тем как записать очередное слово в приёмник, нужно будет очищать его от предыдущего мусора, забивая баксами. Вот что получилось (на фасме):
ASM
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
org 100h
jmp start
 
mes0   db  13,10,'String: $'
mes1   db  13,10,' Words: $'
bMax   db  80               ; макс.размер буфера
bLen   db  0                ; длина строки
bStr   db  80 dup(0)        ; буфер источника
buff   db  32 dup('$')      ; буфер приёмника
 
start:
    mov   dx,mes0           ;
    call  message           ;
    mov   ah,0Ah            ; заполяем источник строкой юзера
    mov   dx,bMax           ;
    int   21h               ;
 
    mov   si,bStr           ; адрес начала строки для LODSB
printWord:                  ;
    call  findSpace         ; заполняем приёмный буфер
    cmp   byte[buff],'$'    ; буфер пустой?
    je    printWord         ;
    mov   dx,mes1           ; в приёмнике что-то есть. мессага!
    call  message           ;
    mov   dx,buff           ; выводим данные из буфера
    call  message           ;
    jmp   printWord         ; ищем сл.слово в источнике
 
stop:                       ;
    mov   al,7              ; бипер..
    int   29h               ;
    xor   ax,ax             ;
    int   16h               ;
    int   20h               ; выход!
 
;нннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннннн
message: ;===================================================
   mov   ah,9           ;
   int   21h            ;
ret                     ;
 
findSpace: ;=================================================
    mov   cx,32         ; очистим приёмный буфер
    mov   al,'$'        ;
    mov   di,buff       ;
    push  di            ;
    rep   stosb         ;
;-----------------------;--
    pop   di            ;
@1: lodsb               ; читаем символ из SI
    cmp   al,0Dh        ; всю строку юзера проверили?
    je    endStr        ;
    cmp   al,' '        ; пробел?
    je    @2            ;
    stosb               ; нет - сохраняем символ в приёмнике
    jmp   @1            ; сл.символ..
@2:                     ;
ret                     ; выход из процедуры!
endStr:                 ; выход из внешнего цикла!
    pop   ax            ; снимаем CALL'овский адрес возврата
    jmp   stop          ;
Вопрос: Вывод символьной строки на экран

Добрый вечер, реализовал программу, условие её такого что нужно из текстового файла прочитать 20 символов начиная с 10-байта в файле. Показать строчку на экране( что у меня не получается!!!!) и записать в новый файл по 4 символа в каждой строчке. Все условие программы у меня реализовано и работает прекрасно, но при выводе строк на экран выдает полнейшую чушь
Помогите разобраться

ASM
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
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
.386
 
stak segment
  db 100 dup (0)
stak ends
 
;сегмент данных 
dseg segment
   txt1 db 'File Name Read: ',0dh,0ah,'$'          ;текст перед запросом на имя файла
   txt2 db 'Not Enter FileName!',0dh,0ah,'$'       ;неуказано ничего в командной строке, например нажали Enter просто
   txt3 db 'Open File Error!',0dh,0ah,'$'          ;ошибка открытия файла
   txt4 db 'Error Create File!',0dh,0ah,'$'        ;ошибка создания файла
   txt5 db 'File Name Write: ',0dh,0ah,'$'         ;текст перед запросом на имя файла
   txt6 db 'Stroka simvolov v file: ',0dh,0ah,'$'  ;символы записываемые в файл
   perehod db 0dh,0ah,'$'                          ;перевод строки и возврат коретки 
 
    buf_ db 0    ;буфер для чтения 4 байт
    des1 dw ?          ;хэндл файла который читаем
    des2 dw ?          ;хэндл файла который создается (tmp.tmp)
    kol  dw 0
    stroch  dw 0
                       ;буфер для файл чтения
     max db 254        ;максимально допустимая
     len db 0          ;действительная длина данных
     buf db 254 dup (0);буфер содержит ввод, заканчивающийся символом CR (ASCII 0dH)
 
                       ;буфер для файл записи
    max2 db 254        ;максимально допустимая
    len2 db 0          ;действительная длина данных
    buf2 db 254 dup (0);буфер содержит ввод, заканчивающийся символом CR (ASCII 0dH)
    
dseg ends
cseg segment
assume cs:cseg, ds:dseg, ss:stak
 
.386
start:
                 ;настройка DS на сегмент данных
 mov ax,dseg
 mov ds,ax
 
                ;выводим приглашение 
 lea dx,txt1    ;текст txt1
 call t1        ;процедура вывода текста 
 
                ;запрос на ввод строки имя файла
 mov ah,0ah
 lea dx,max
 int 21h
 jc exit_1
 
 
 cmp [len],0  ;если len = 0 значит не вводили в строке а нажали Enter
 jne d1       ;если len <> 0 то d1
 jmp exit_1   ;если 0 то мы ничего ни ввели в командной строке, выход
 
 
d1: 
 lea dx,perehod      ;строка perehod
 call t1             ;вывод текста
 
                     ;что то ввели в строке, проверим мож файл?
                     ;для это поместим в конец строки символ с кодом 0
 lea si,buf          ;в SI адрес буфера buf
 xor bx,bx           ;обнулим BX
 mov bl,[len]        ;длину строки LEN в BL
 mov al,0            ;сделаем AL = 0
 mov ds:[si+bx],al   ;в строке которую мы ввели в конце есть символ 0Dh, адрес ее это буфер buf + дина LEN
                     ;положим туда AL, а это 0, для открытия файла   
                     
 
                     ;AL = режим открытия, AL = 0 чтобы открыть для чтения
 mov ax,3d00h
 lea dx,buf          ;имя файлов, может включать и путь 
 int 21h
 jnc create_file     ;если не было ошибок при открытии
 
 
                   ;если файла нет или ошибка была при открытии,выводим текст txt3
 lea dx,txt3
 call t1
 jmp exit_dos      ;на метку, выход в дос
 
 
                   ;не было ошибок открытия, продолжаем 
create_file:
                   ;сохраним хэндл файла (описатель)
 mov [des1],ax
 
                   ;выводим приглашение 
 lea dx,txt5       ;текст txt5
 call t1           ;процедура вывода текста 
 
                   ;опрос на ввода имени для записи  
 mov ah,0ah
 lea dx,max2
 int 21h 
 jnc create2       ;если были ошибки, то закроем файл 1 и выходим      
 
 cmp [len2],0      ;если len2 <> 0 то d1
 je close2
 
 
create2: 
 lea dx,perehod    ;строка perehod
 call t1           ;вывод текста
 
                   ;подготовка к созданию файла
                   ;что то ввели в строке, проверим мож файл?
                   ;для это поместим в конец строки символ с кодом 0
 lea si,buf2       ;в SI адрес буфера buf2
 xor bx,bx            ;обнулим BX
 mov bl,[len2]        ;длину строки LEN в BL
 mov al,0             ;сделаем AL = 0
 mov ds:[si+bx],al    ;в строке которую мы ввели в конце есть символ 0Dh, адрес ее это буфер buf + дина LEN
                      ;положим туда AL, а это 0, для открытия файла   
                                     
                      ;создадим файл указанный в строке buf2
                      ;Вход AH = 3cH
                      ;DS:DX = адрес строки ASCIIZ с именем файла
                      ;CX = атрибут файла
 mov ah,3ch 
 mov cx,20h
 lea dx,buf2
 int 21h
 jnc vse_ok           ;не было ошибок при создании файла
 
                      ;если ошибки при создании файл 
 lea dx,txt4
 call t1 
 jmp close2  ;на метку закрытия первого файла
 
 
vse_ok:
                      ;сохраним хэндл файла (описатель) (tmp.tmp)
 mov [des2],ax
 
 
 
 
 
                      ;организуем цикл для чтения и записи
 lea dx,txt6
 call t1
 
 mov ah,42h
 mov bx,[des1]
 mov al,0
 mov cx,0
 mov dx,10
 int 21h
 
cikl: 
 
 mov ah,3fh
 mov bx,[des1]
 lea dx,buf_
 push dx
 mov cx,1
 int 21h  
 jc close1 ;если при чтении файла была ошибка то на метку close1
 
                     ;при чтении в AX возсращается реальное считанное кол-во байт
                     ;если 0 то закрываем файлы 
 cmp ax,0
 je close1
 
                     ;если встретили не конец строки 
 cmp [buf_],0Dh
 jne write1
 
                     ;если встретили конец строки 
 jmp close1 
 
 
                
write1:
; Здесь вывод символа на экран но он не работает!!! точнее работает не коректно!  
  pop dx
  push ax
  mov ax,dx  
  add ax,41h                
  int 29h
  pop ax
; запись в файл ... (работает)
 mov cx,ax 
 mov ah,40h
 mov bx,[des2]
 lea dx,buf_
 int 21h
 
 mov bp,[kol]
 cmp bp,19
 jz short close1
 inc bp
 mov [kol],bp
 
 mov bp,[stroch]
 cmp bp,3
 jz short otv
 inc bp
 mov [stroch],bp
                      ;прыгаем на метку cikl 
 jmp cikl
 
otv:
 mov ah,40h
 mov bx,[des2] 
 lea dx,perehod
 mov cx,2
 int 21h
 
 mov bp,0
 mov [stroch],bp
 jmp cikl  
 
;закрываем файл (временный файл tmp.tmp) 
close1:
;Вход AH = 3eH
;BX = описатель файла
 mov ah,3eh
 mov bx,[des2]
 int 21h 
   
;закрываем файл (который указан в командной строке)  
close2:
;Вход AH = 3eH
;BX = описатель файла
 mov ah,3eh
 mov bx,[des1]
 int 21h 
 jmp exit_dos ;на метку выход
 
 
 
exit_1:
   lea dx,txt2      ;не ввели что либо в строке при опросе, выводим текст txt2
   call t1
 
 
exit_dos:           ;выход в дос 
   mov ax,4c00h
   int 21h
 
 
t1 proc             ;процедура вывода текста, в DX уже есть строка
   mov ah,09h
   int 21h
   ret 
t1 endp 
 
cseg ends 
 
 
end start
Ответ: guard_2007,
ASM
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
235
236
237
238
239
240
241
242
243
244
245
246
model small
 stack 256
dataseg
   txt1 db 'File Name Read: ',0dh,0ah,'$'          ;текст перед запросом на имя файла
   txt2 db 'Not Enter FileName!',0dh,0ah,'$'       ;неуказано ничего в командной строке, например нажали Enter просто
   txt3 db 'Open File Error!',0dh,0ah,'$'          ;ошибка открытия файла
   txt4 db 'Error Create File!',0dh,0ah,'$'        ;ошибка создания файла
   txt5 db 'File Name Write: ',0dh,0ah,'$'         ;текст перед запросом на имя файла
   txt6 db 'Stroka simvolov v file: ',0dh,0ah,'$'  ;символы записываемые в файл
   perehod db 0dh,0ah,'$'                          ;перевод строки и возврат коретки 
 
    buf_ db 0          ;буфер для чтения 4 байт
    des1 dw ?          ;хэндл файла который читаем
    des2 dw ?          ;хэндл файла который создается (tmp.tmp)
    kol  dw 0
    stroch  dw 0
                       ;буфер для файл чтения
     max db 254        ;максимально допустимая
     len db 0          ;действительная длина данных
     buf db 254 dup (0);буфер содержит ввод, заканчивающийся символом CR (ASCII 0dH)
 
                       ;буфер для файл записи
    max2 db 254        ;максимально допустимая
    len2 db 0          ;действительная длина данных
    buf2 db 254 dup (0);буфер содержит ввод, заканчивающийся символом CR (ASCII 0dH)
 
codeseg
 .386
start:
                 ;настройка DS на сегмент данных
 mov ax,@data
 mov ds,ax
 
                ;выводим приглашение 
 lea dx,txt1    ;текст txt1
 call t1        ;процедура вывода текста 
 
                ;запрос на ввод строки имя файла
 mov ah,0ah
 lea dx,max
 int 21h
 jc exit_1
 
 
 cmp [len],0  ;если len = 0 значит не вводили в строке а нажали Enter
 jne d1       ;если len <> 0 то d1
 jmp exit_1   ;если 0 то мы ничего ни ввели в командной строке, выход
 
 
d1: 
 lea dx,perehod      ;строка perehod
 call t1             ;вывод текста
 
                     ;что то ввели в строке, проверим мож файл?
                     ;для это поместим в конец строки символ с кодом 0
 lea si,buf          ;в SI адрес буфера buf
 xor bx,bx           ;обнулим BX
 mov bl,[len]        ;длину строки LEN в BL
 mov al,0            ;сделаем AL = 0
 mov ds:[si+bx],al   ;в строке которую мы ввели в конце есть символ 0Dh, адрес ее это буфер buf + дина LEN
                     ;положим туда AL, а это 0, для открытия файла   
                     
 
                     ;AL = режим открытия, AL = 0 чтобы открыть для чтения
 mov ax,3d00h
 lea dx,buf          ;имя файлов, может включать и путь 
 int 21h
 jnc create_file     ;если не было ошибок при открытии
 
 
                   ;если файла нет или ошибка была при открытии,выводим текст txt3
 lea dx,txt3
 call t1
 jmp exit_dos      ;на метку, выход в дос
 
 
                   ;не было ошибок открытия, продолжаем 
create_file:
                   ;сохраним хэндл файла (описатель)
 mov [des1],ax
 
                   ;выводим приглашение 
 lea dx,txt5       ;текст txt5
 call t1           ;процедура вывода текста 
 
                   ;опрос на ввода имени для записи  
 mov ah,0ah
 lea dx,max2
 int 21h 
 jnc create2       ;если были ошибки, то закроем файл 1 и выходим      
 
 cmp [len2],0      ;если len2 <> 0 то d1
 je close2
 
 
create2: 
 lea dx,perehod    ;строка perehod
 call t1           ;вывод текста
 
                   ;подготовка к созданию файла
                   ;что то ввели в строке, проверим мож файл?
                   ;для это поместим в конец строки символ с кодом 0
 lea si,buf2       ;в SI адрес буфера buf2
 xor bx,bx            ;обнулим BX
 mov bl,[len2]        ;длину строки LEN в BL
 mov al,0             ;сделаем AL = 0
 mov ds:[si+bx],al    ;в строке которую мы ввели в конце есть символ 0Dh, адрес ее это буфер buf + дина LEN
                      ;положим туда AL, а это 0, для открытия файла   
                                     
                      ;создадим файл указанный в строке buf2
                      ;Вход AH = 3cH
                      ;DS:DX = адрес строки ASCIIZ с именем файла
                      ;CX = атрибут файла
 mov ah,3ch 
 mov cx,20h
 lea dx,buf2
 int 21h
 jnc vse_ok           ;не было ошибок при создании файла
 
                      ;если ошибки при создании файл 
 lea dx,txt4
 call t1 
 jmp close2  ;на метку закрытия первого файла
 
 
vse_ok:
                      ;сохраним хэндл файла (описатель) (tmp.tmp)
 mov [des2],ax
 
 
 
 
 
                      ;организуем цикл для чтения и записи
 lea dx,txt6
 call t1
 
 mov ah,42h
 mov bx,[des1]
 mov al,0
 mov cx,0
 mov dx,10
 int 21h
 
cikl: 
 
 mov ah,3fh
 mov bx,[des1]
 lea dx,buf_
; push dx
 mov cx,1
 int 21h  
 jc close1 ;если при чтении файла была ошибка то на метку close1
 
                     ;при чтении в AX возсращается реальное считанное кол-во байт
                     ;если 0 то закрываем файлы 
 cmp ax,0
 je close1
 
                     ;если встретили не конец строки 
 cmp [buf_],0Dh
 jne write1
 
                     ;если встретили конец строки 
 jmp close1 
 
 
                
write1:
; Здесь вывод символа на экран но он не работает!!! точнее работает не коректно!  
;pop dx
  push ax
; mov ax,dx  
  mov al,[buf_]
;add ax,41h                
  int 29h
  pop ax
 
;запись в файл ... (работает)
 mov cx,ax 
 mov ah,40h
 mov bx,[des2]
 lea dx,buf_
 int 21h
 
 mov bp,[kol]
 cmp bp,19
 jz short close1
 inc bp
 mov [kol],bp
 
 mov bp,[stroch]
 cmp bp,3
 jz short otv
 inc bp
 mov [stroch],bp
                      ;прыгаем на метку cikl 
 jmp cikl
 
otv:
 mov ah,40h
 mov bx,[des2] 
 lea dx,perehod
 mov cx,2
 int 21h
 
 mov bp,0
 mov [stroch],bp
 jmp cikl  
 
;закрываем файл (временный файл tmp.tmp) 
close1:
;Вход AH = 3eH
;BX = описатель файла
 mov ah,3eh
 mov bx,[des2]
 int 21h 
   
;закрываем файл (который указан в командной строке)  
close2:
;Вход AH = 3eH
;BX = описатель файла
 mov ah,3eh
 mov bx,[des1]
 int 21h 
 jmp exit_dos ;на метку выход
 
 
 
exit_1:
   lea dx,txt2      ;не ввели что либо в строке при опросе, выводим текст txt2
   call t1
 
 
exit_dos:           ;выход в дос 
   mov ax,4c00h
   int 21h
 
 
t1 proc             ;процедура вывода текста, в DX уже есть строка
   mov ah,09h
   int 21h
   ret 
t1 endp
 
end start
поправил немного
Это задумывалось ?
Вопрос: Вывод строк таблицей и нахождение знаков пробелов в каждой строке

Вводим строки до тех пор пока не будет введена строка end. Проверить содержит ли строка знаки препинания если да,добавить все встречающие знаки в начало строки , отделить их от исходной строки символов подчеркивания. И вывести таблицей
Например,
Исходная строка Обработанная строка строка 1 строка 1 обработанная строка 2 строка 2 обработанная строка n строка n обработанная
НЕ МОГУ СДЕЛАТЬ ВЫВОД СТРОК ТАБЛИЦЕЙ И НАХОЖДЕНИЕ ЗНАКОВ ПРОБЕЛОВ В КАЖДОЙ СТРОКЕ

ЕСТЬ ЧАСТЬ КОДА НО НЕ МОГУ ВСЕ ЭТО СКЛЕИТЬ

Ввод строк
Код C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
#include <string.h>
 
int main()
{
   char s[100];
   printf("Enter a string: " );
   gets(s);
   while(strcmp(s, "end") != 0)
   {
      printf("Your string: %s\n\n", s);
      printf("Enter a string: " );
      gets(s);
   } 
    
   return 0; 
}

Нахождение знака препинания
Код C
1
2
3
4
5
6
7
8
for(int i=0;s[i]!='\0';i++)
{
    if(s[i]=='.'||s[i]==','|| s[i]=='?'||s[i]=='!'||s[i]==':'||s[i]==';'||s[i]=='-')
    {
     
        printf("%c",s[i]);
    }
}
Ответ: Можно обработанные строки пихать в массив char*[] и потом выводить таблицей.
По поводу поиска пробелов и знаков препинания:
есть такая библиотека <ctype.h>, а там фукции
для проверки на знак препинания (возвращает true\false)
Код C
1
int ispunct(int c);
вот это
Код C
1
 if(s[i]=='.'||s[i]==','|| s[i]=='?'||s[i]=='!'||s[i]==':'||s[i]==';'||s[i]=='-'
заменяется на
Код C
1
if (ispunct(s[i])
и для проверки на пробел (возвращает truе\false)
Код C
1
int isspace(int c);
Вопрос: Создать подпрограмму, определяющую, содержится ли одна заданная строка в другой заданной строке

Разработать подпрограмму, которая определяет, содержится ли одна заданная строка в другой заданной строке, и если да, то, начиная с какой позиции. Разработать программу, которая вводит с клавиатуры две строки и сообщает, содержится ли одна из них в другой и сколько раз.

не получается с самой подпрограммой!

Код ASM
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
locals __       ; определение префикса локальных переменных
.model SMALL    ; определение модели памяти
stack 200h      ; задаем размер стека - 512 байт
 
dataseg         ; определяем сегмент данных
COUNT_STR dw 0  ; число введенных строк
 
INFO_MESSAGE    db 0AH, 0DH
                db "Enter two lines"
                db 0AH, 0DH, '$'
 
INVITE_1        db 0Ah, 0Dh
                db "Enter the first line: $"
INVITE_2        db 0Ah, 0Dh
                db "Enter the second line: $"
 
INVITE_RESULT_1 db 0Ah, 0Dh
                db "YES! "
                db 0Ah, 0Dh, '$'
                
INVITE_RESULT_2 db 0Ah, 0Dh
                db "NO! "
                db 0Ah, 0Dh, '$'
 
 
PRESS           db 0Ah, 0Dh
                db "Exit - any $"
 
STR_1           db 80, ?, 82 dup ( ? )
STR_2           db 80, ?, 82 dup ( ? )
BUFFER          db 80, ?, 82 dup ( ? )
 
REPETITION      dw 0h                   ; количество одной строки в другой
 
 
codeseg                     ; определение сегмента кода
startupcode                 ; установление регистров DS и SS
 
lea DX, INFO_MESSAGE        ; в DX занести адрес строки
mov AH, 09h                 ; в АН занести номер функции
int 21h                     ; вызов прерывания
 
;ввод строк с клавиатуры 
 
InputStr:
    lea DX, INVITE_1        ; в DX занести адрес строки
    mov AH, 09h             ; в АН занести номер функции
    int 21h                 ; вызов прерывания
    lea DX, STR_1           ; в DX занести буфер для ввода
    mov AH, 0Ah             ; в АН занести номер функции
    int 21h                 ; вызов прерывания
    lea DX, INVITE_2        ; в DX занести адрес строки
    mov AH, 09h             ; в АН занести номер функции
    int 21h                 ; вызов прерывания
    lea DX, STR_2           ; в DX занести буфер для ввода
    mov AH, 0Ah             ; в АН занести номер функции
    int 21h                 ; вызов прерывания
 
 
FIND:
    ;;;; ПОИСК ;;;;
    lea DI,STR_1 
    lea SI,STR_2
    mov DX,REPETITION
 
    push DI            
    push SI
    push DX
    
    call StrFind    ; вызываем подпрограмму
    cmp DX, word ptr 0
    je NO
YES:
    lea DX, INVITE_RESULT_1 ; в DX занести адрес строки
    mov AH, 09h ; в АН занести номер функции 
    int 21h ; вызов прерывания
    jmp metka1
NO:
    lea DX, INVITE_RESULT_2 ; в DX занести адрес строки
    mov AH, 09h ; в АН занести номер функции 
    int 21h ; вызов прерывания              
    
metka1:
; пауза перед выходом из программы 
    lea DX, PRESS ; в DX занести адрес строки
    mov AH, 09h ; в АН занести номер функции 
    int 21h ; вызов прерывания
    mov AH, 08h ; в АН занести номер функции
    int 21h ; вызов прерывания
 
QUIT:
exitcode 0                  ; вернуть в ОС код возврата - 0
 
    
; подпрограмма поиска одной строки в другой
            ; аргументы 
            ; __num1 - индекс первой строки;
            ; __num2 - индекс второй строки;
            ; выходные значения 
            ; результат в REPETITION
 
StrFind proc near
 arg __num1:word, __num2:word,__num3:word = __ArgSize
 local  __FLAG: byte, __COUNT: word = __LocSize
 
push BP                     ; сохранить значение базового указателя
mov BP, SP                  ; базовому указателю присваиваем указатель стека
push SI DI                  ; сохраняем значение регистров SI и DI
push CX
 
mov SI, 4
mov     DI, 4
 
mov __FLAG, 0
mov __COUNT, 0
xor DX, DX
mov CX, __num1 + 1
mov DX, __num3
 
; цикл поиска шаблона  
BB:     xor AX, AX
    mov AX, __num1[DI]  ; в АL занести текущий символ
    cmp AX, __num2[SI]  ; сравнение символа строки и шаблона
    je TY               ; символы равны
    mov __FLAG, 0       ; символы не равны
    mov __COUNT, 0      ; обнуляем количество равных символов
    mov SI, 4           ; возвращаемся в начало шаблона
    jmp CONTINUE        ; перейти по метке
 
TY:
    mov __FLAG, 1           ; символы равны
    add SI,word ptr  2              ; переходим к следующему символу шаблона
    inc __COUNT         ; увеличиваем кол-во проверенных символов
    mov AX, __num2 + 1; в AL занести длину шаблона
    cmp __COUNT, AX     ; сравниваем длину шаблона и кол-во проверенных символов
    je GO               ; если нашли совпадение, то выходим их цикла
 
CONTINUE:
    add  DI, word ptr 2             ; переходим к следующему символу строки
    loop BB             ; переход на следующую итерацию
 
GO:
    cmp __FLAG, 1
    je YESS
    jmp NOO
YESS:   
    inc DX          ; наращиваем количество повторений одной строки в другой
    xor SI, SI          ; очистить регистр SI
    mov SI, 4           ; в SI занести смещение в шаблоне
    add DI, word ptr 2              ; переходим к следующему символу строки
    dec CX
    cmp CX, word ptr 0
    je BB
NOO:
    xor SI, SI          ; очистить регистр SI
    mov SI, 4           ; в SI занести смещение в шаблоне
    mov DI, word ptr 2
    dec CX              ; переходим к следующему символу строки
    cmp CX, word ptr 0
    je BB
; конец цикла 
 
StrFindRet:
pop CX              
pop DI SI               ; восстанавливаем значения регистров 
pop BP
ret __ArgSize           ; убираем параметры
StrFind endp
 
 
 
end                     ; конец программы 
Ответ: Смотри. Рисуем алгоритм вообще. Абстрактно.
Код ASM
1
2
3
4
5
6
7
8
9
10
11
12
13
Пусть DI - адрес первого символа длинной строки
      DX - длина длинной строки
      SI - адрес первого символа короткого шаблона
      CX - длина короткого шаблона
 
 
CYKL:   CMP CX,DX   ;Если длина шаблона больше остатка строки,
    JA  DONE    ; то все, мы закончили
    Поискать шаблон [SI] в строке [DI], регистры CX DX SI DI сохранить
    INC DI  ;Продвинулись по строке вправо
    DEC DX  ;Остаток строки уменьшился
    JMP CYKL
DONE:
Добавлено через 2 минуты
Осталось только нарисовать внутренний алгоритм. В нем будет цикл CX раз
Вопрос: Замена каждой строки, состоящей из одного или нескольких пробелов, одним пробелом

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

Код 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
#include <stdio.h>
 
#define IN 1 /* внутри слова */
#define OUT 0 /* снаружи слова */
 
main(){
 
    /* замена строки, состоящей из пробелов, одним пробелом */
 
    int character; /* входной символ */
 
    int spaceCounter = 0; /* счётчик пробелов */
    int charCounter = 0; /* счётчик символов внутри строки */
 
    int state = OUT; /* положение внутри (IN) или снаружи (OUT) строки */
 
    while((character = getchar()) != EOF){
 
        if(character == '\n')
            state = OUT;
        else if (state == OUT)
            state = IN;
 
        if(state == IN){
 
            putchar(character); /* вывод символа на экран */
 
            charCounter++;  /* подсчёт символов внутри строки */
 
            if(character == ' ')
                spaceCounter++; /* подсчёт пробелов */
 
        }
        else {
 
            if((spaceCounter == charCounter) && spaceCounter > 0){ /* строка состоит только из пробелов */
                
                putchar('\r'); /* возврат каретки в начало строки */
                putchar(' ');
 
            }
 
            putchar(character);
 
        } 
 
    }
}
От конструкции state == IN, state == OUT можно избавиться, но с ней, мне кажется, удобнее.
Ответ: Я новичок в программировании, тоже начал с K&R. НРАИЦЦА! В отличие от всяких Прата, Шилдтов и т. д., где разжевано настолько, что уже и не усваивается, здесь все четко и по делу.

Посмею предложить свое видение задачи и ее решение.

Формулировка: «Напишите программу для копирования входного потока в выходной с заменой каждой строки, состоящей из одного или нескольких пробелов, одним пробелом».
Соглашения: Сразу оговорюсь, что для удобства тестирования программы и улучшения визуализации ее вывода будем заменять пробел звездочкой (*). Везде в исходном коде и в этом сообщении под '*' понимается ' '. Чтобы получить рабочую программу, в исходном коде нужно заменить каждую '*' на ' '.
Рассуждаем о задаче: Что понимаем под строкой? На пару страниц выше в данной книге говорится, что строка — это последовательность символов (от нуля и больше) входного потока, оканчивающаяся символом конца строки (\n). В таком случае получается, что всякий раз, когда строка представляет собой последовательность «'*'-k раз + '\n'», где k >= 1, она должна быть выведена как одна звездочка (без символа конца строки). Такие строки будем называть пробельными. То есть, например, если имеем:

"*\n" выводится как '*', или
"******\n" выводится как '*'.

Следующие случаи не считаются подходящими под определения пробельной строки и поэтому выводятся как есть:

"\n" выводится как "\n" (это не пробельная строка, а пустая),
"A******\n" выводится как "A******\n", здесь и далее в сообщении 'A'— любой символ != EOF, '*' или '\n',
"****A*****\n" выводится как "****A*****\n" и т. д.

Ограничения на языковые средства: данное задание дается в первой главе K&R, в той ее части, где еще ничего не говорится про массивы, функции, указатели и т. д. Поэтому будем обходится без всего этого, по минимуму, только тем, о чем в книге к моменту постановки задачи было явно рассказано. Возможно, глупо себя ограничивать таким образом, однако если вы — новичок, то у вас нет выбора. К тому же задача в той ее интерпретации, в какой я привел ее выше, вполне решаема с учетом указанных ограничений.

Код:
Код 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
#include <stdio.h>
#define ON  1
#define OFF 0
 
int main(void)
{
    char flag = ON;
    short c;
    int spaces = 0;
 
    while((c = getchar()) != EOF) {
        if(flag) {
            if(c == '*')
                spaces++;
            else if(c == '\n') {
                if(spaces != 0) {
                    spaces = 0;
                    putchar('*');
                }
                else
                    putchar(c);
            }
            else {
                flag = OFF;
                for(; spaces > 0; spaces--)
                    putchar('*');
                putchar(c);
            }
        }
        else {
            if(c == '\n')
                flag = ON;
            putchar(c);
        }
    }
    getchar();
    return 0;
}
Пояснения к коду: Я использую флаг с двумя состояниями. flag = ON означает, что текущая строка, возможно, является пробельной. В таком состоянии флаг будет находиться до тех пор, пока в данной строке не появится любой иной символ, отличный от EOF, '*' или '\n'. Каждый раз при появлении во входном потоке '\n' флаг устанавливается в состояние ON. Также сама переменная flag инициализируется значением ON, чтобы иметь возможность обнаружить пробельную строку, если она будет самой первой во входном потоке.
В переменной spaces накапливается количество пробелов('*') в текущей строке. Если например вводится строка:

"********4\n",

то до того как появится '4' программа не может вывести звездочки, ведь она еще не знает появятся ли в этой строке непробелы или нет. В случае, если они появятся (как четверка в примере), то перед этим символом нужно вывести уже введенное количество звездочек, а также снять флаг (перевести в OFF), ведь строка уже явно не пробельная.

Надеюсь мои пространные объяснения кому-нибудь окажутся полезными.
Вопрос: Выделения из исходной строки подстроки символов

Написать программу выделения из исходной строки подстроки символов заданной длины с указанного номера позиции, Pascal-string.
Как переделать из Pascal-string в Z-string?


Код ASM
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
;Часть строки, следующую за первым вхождением заданного символа переписать
;в обратном порядке заданное число раз;(использовать процедуры)
.686
.model flat,stdcall
option casemap:none
 
mem_alloc proto :dword,:dword,:dword ; прототипы функций, используемых в программе
reverce proto :dword,:dword,:dword,:dword,:dword
 
include \masm32\include\msvcrt.inc
include \masm32\include\windows.inc
include \masm32\include\user32.inc
 
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\user32.lib
 
.data
msg db 'Введите строку',0dh,0ah,1 ; единицы в конце строк нужны для того, чтобы функция CharToOem могла перекодировать весь текст за один раз
msg1 db 'Введите позицию символа начала подстроки ',0dh,0ah,1 ; до символа нуля
msg2 db 'Введите количество повторов подстроки',0dh,0ah,1
msg_exit db 0ah,'Для выхода нажмите клавишу ESC, для повторного ввода нажмите любую другую клавишу',0dh,0ah,1
msg_no db 0ah,'Позиция символа введена неверно',0dh,0ah,0
crlf db 0dh,0ah,0 ; знаки первода строки и каретки, будут использованы после ввода символа для 
; перевода курсора на новую строку
fmt db '%u',0
 
.code
 
start proc 
; локальные переменные
local string[MAX_PATH]:byte ; буффер для ввода строки, 260 байт
local position,str_len,crep:dword ; переменные для хранения начальной позиции подстроки, длины
; строки и количества повторений соответственно
 
invoke CharToOem,offset msg,offset msg ; функция перекодирует текст сообщений из кодировки CP1251 в CP866 для правильного отображения в консоли
mov msg+sizeof msg-1,0 ; заменим единицы в конце текстовых сообщений на нули
mov msg1+sizeof msg1-1,0
mov msg2+sizeof msg2-1,0
mov msg_exit+sizeof msg_exit-1,0
 
@gets:
 
invoke printf,offset msg ; выводим на экран приглашение к вводу строки
 
lea esi,string ; регистр esi указывает на начало буфера для ввода строки
invoke gets,esi ; функция ввода строки
 
invoke strlen,esi ; измерим длину введённой строки
mov str_len,eax ; и сохраним полученное значение в переменной и регистре
mov edi,eax
dec edi ; уменьшим на единицу полученное значение, так как нумерация символов в строке идёт с нуля
 
invoke printf,offset msg1 ; вывод на экран приглашения к вводу значения позиции начала подстроки
 
invoke scanf,offset fmt,addr position ; функция преобразует введённые цифры в число, в сответствии с указанным форматом ( в нашем случае
dec position ; - беззнаковое десятичное число)
cmp position,edi ; уменьшим введённое значение на 1 , сравним его с длиной строки
jb m1 ; если оно больше или равно длины строки
 
invoke printf,offset msg_no ; выведем сообщение об ошибочном вводе
jmp exit
 
m1:
invoke printf,offset msg2 ; иначе продолжаем выводом приглашения к вводу количества повторов подстроки
invoke scanf,offset fmt,addr crep 
 
dec crep ; полученное значение уменьшаем на единицу
 
mov ebx,str_len ; вычислим длину подстроки
sub ebx,position
cmp ebx,1
jnz m2
 
invoke printf,offset msg_no ; выведем сообщение об ошибочном вводе если длина подстроки равна единице
jmp exit
 
m2:
invoke mem_alloc,crep,ebx,str_len ; вызовем функцию выделения памяти под новую строку
; передав ей в качестве параметров кол-во повторов подстроки, её длину и длину исходной строки
 
mov ebx,eax ; и сохраним возращённый указатель на выделенный блок памяти в регистре ebx
 
invoke reverce,esi,ebx,position,str_len,crep
 
invoke printf,ebx ; выводим строку на экран
invoke free,ebx ; освобождаем память
exit:
invoke printf,offset msg_exit ; выводим сообщение о способе завершения программы
 
invoke _getch ; ожидание нажатия клавиши пользователем
cmp al,1bh
je @f
invoke getchar
jmp @gets
@@:
invoke _exit ; завершение программы
 
start endp
 
; —-----------------------------------------------------------------------
 
reverce proc uses ebx pstr:dword,pnewstr:dword,psubstr:dword,szstr:dword,crep
 
mov esi,pstr ;
переданный в процедура указатель на исходную строку
mov edi,pnewstr ; указатель на выделенный блок памяти
mov ecx,psubstr ; номер начального символа подстроки
rep movsb ; копируем исходную строку до начала подстроки в новую
 
mov ecx,szstr ; размер исходной строки
sub ecx,psubstr ; получаем размер подстроки
mov edx,ecx ; сохраняем в регистре edx для повторного использования
mov ebx,edi ; указатель на начало подстроки сохраняем в ebx
 
m1:
lodsb ; в цикле заносим в стек символы подстроки, подлежащие реверсированию
push ax
loop m1
 
mov ecx,edx ; восстанавливаем счётчик
m2:
pop ax ; перезаписывем в новую строку в обратном порядке ( последний символ строки будет лежать в стеке первым)
stosb
loop m2
 
mov esi,ebx ; устанавливаем указаетель на начало перевернутой подстроки
mov ecx,crep ; количество повторов подстроки
; регистр edi указывает на первый байт после последнего символа скопированной строки
m3:
push ecx ; сохранив счётчик в стеке
mov ecx,edx
rep movsb ; копируем подстроку 
pop ecx ; нужное число раз
loop m3
xor al,al ; в конец новой строки записываем символ нуля
stosb
 
ret ; возврат из процедуры
reverce endp
 
; —-----------------------------------------------------------------------
 
mem_alloc proc var1:dword,var2:dword,var3:dword
 
mov eax,var1 ; количество повторов умножаем на
mul var2 ; длину подстроки
add eax,var3 ; прибавляем к произведению длину строки
inc eax ; прибавляем единицу (для записи нулевого байта - признака конца новой строки)
 
invoke malloc,eax ; выделяем память под формируемую строку
 
ret
mem_alloc endp
end start
Ответ: edi указывает на Pascal-строку
Код ASM
1
2
3
4
5
6
7
8
    push    edi
    movzx   ecx, byte ptr [edi]
    lea esi, 1[edi]
    cld
rep movsb
    mov al, cl
    stosb
    pop edi
и вот он уже указывает на Z-строку

Добавлено через 7 минут
Сообщение от anna_smith
invoke strlen,esi ; измерим длину введённой строки
Сообщение от anna_smith
xor al,al ; в конец новой строки записываем символ нуля
stosb
Че-то это мало похоже на работу с Паскалевскими строками.
Вопрос: Перезаписать строку в QFile

Приветствую всех.
Подскажите пожалуйста как правильно перезаписать строку в файле.
У меня есть *txt файл где лежат пути для работы, вот такого вида (число - определенный параметр для работы и путь к файлам)

10 C:/filesdock/writeparamfull
11 C:/Users/Descktop
15 D:/info/param
43 D:/paramzero/needwrite


При загрузке файла надо сохранить путь вместо того, по которому будет первоначальное открытие. В данном примере это третья строка 15 D:/info/param
Делать пытаюсь двумя способами и оба провальные.
Первый: открываю файл и шагаю по строчно вычитывая и проверяя на нужный параметр, при нахождении выхожу, запомнив позицию с которой начиналась строка. Получив новый путь, сдвигаюсь на начало нужной строки и записываю новую.

Код C++ (QT)
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
Qfile path_info_file;
Int index_need, pos_index;
QString path_info_str;
 
path_info_file.setFileName("info.txt");
if(!path_info_file.isOpen())
{
   path_info_file.open(QIODevice::ReadWrite);
   while(!path_info_file.atEnd())
      {
          pos_index = path_info_file.pos();
          path_info_str = path_info_file.readLine();
         QStringList list = path_info_str.split(" ");
                index_need = list.at(0).toInt();
                path_info_str = list.at(1);
                if(index_need == 15)
                               {
                                 //нашли что нам надо
                                  break;
                                }
}
//бла бла бла делаем что нам надо и поулчаем путь к файлу QString path_fileName
//который равен, допустим D:\qtproject
 
path_info_file.seek(index_need);
path_info_file.write("15 " + path_fileName.toLatin1() + "\n");
path_info_file.close();
на выходе получается наложение строк друг на друга и сжирание части названий. Вот так выглядит.
10 C:/filesdock/writeparamfull
11 C:/Users/Descktop
15 D:/qtproject amzero/needwrite

Предполагаю что это происходит из-за разницы размера строк, как исправить пока не знаю.

Второй вариант это делать с помощью QByteArray, вычитывая все строки и записывая их в переменную QByteArray кроме той, которая подойдет по параметрам. Найдя нужную записать ее новую вариацию, потом сделать resize(0) чтобы удалить старые строки и заново перезаписать файл.
Код C++ (QT)
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
Qfile path_info_file;
QString path_info_str, yrt;
QByteArray baff;
 
 path_info_file.setFileName("info.txt");
if(!path_info_file.isOpen())
{
   path_info_file.open(QIODevice::ReadWrite);
   while(!path_info_file.atEnd())
      {
            path_info_str = path_info_file.readLine();
           QStringList list = path_info_str.split(" ");
                index_need = list.at(0).toInt();
                path_info_str = list.at(1);
                if(index_need == 15)
                {
                   //нашли что нам надо
                   yrt = "";
                   yrt = "15 “ + path_fileName.toLatin1() + “\n";
                   qDebug() << "строка: " << yrt; //смотрю что на выходе
                   baff.append(yrt);
                   yrt = "";
                   path_info_str = " ";
                }
                else
                 {
                      qDebug() << "строка: " << yrt; //смотрю что на выходе
                      baff.append(yrt);
                      yrt = "";
                      path_info_str = ""
                 }
}
qDebug() << "buf" << baff; //проверяю. Что поулчилось
в итоге я смотрю на наличие пробелов и переносов строк при добавлении и вижу что все хорошо и правильно и строку 15 D:/info/param мы заменили за 15 D:/qtproject

строка: “10 C:/filesdock/writeparamfull

строка: “11 C:/Users/Descktop

строка: “15 D:/qtproject

строка: “43 D:/paramzero/needwrite


в дебуге тоже все хорошо

buf «10 C:/filesdock/writeparamfull
11 C:/Users/Descktop
15 D:/qtproject
43 D:/paramzero/needwrite”


А открываю файл и вижу что строки налипли друг на друга как будто переноса и не было!
C:/filesdock/writeparamfull
11 C:/Users/Descktop
15 D:/qtproject43 D:/paramzero/needwrite


Как записать правильно, подскажите пожалуйста, что я упускаю? Заранее спасибо!

Добавлено через 21 минуту
UPD. нашел ошибку, одна из строк не очищалась. Вариант с QbyteArray рабочий, кому может быть пригодится. только в первом if yrt = ""; path_info_str = " "; надо написать path_info_str = "";ну или везде поставить .clear();
Ответ:
Сообщение от ArmanPrestige
Как вариант можно считать построчно файл в QStringList/QList<QByteArray>, изменить, что надо и потом записать заново. Это если файл не большой.
Ну вот у меня как раз корректно заработал второй вариант что я написал. Считывать файл по строчно в QByteArray, заменяя находу нужную строку и перезаписывая файл в конце.
Сообщение от ArmanPrestige
А вообще, может удобнее будет работать с XML/JSON?
Не вижу смысла заморачиваться из-за 4-5 строк. Возможно если записать больше параметров или расширить файл до бОльшего количества строк, то возможно варианты с xml\json будет лучше.
Сообщение от Rius
Криво оно как-то выглядит.
Вот вариант похожего с QSettings, который и предназначен для хранения параметров между запусками:
Может быть и криво, я ж не претендую на идеальность решения. QSettings рассматривал, но не стал углубляться. покопаюсь на досуге, возможно и поудобнее будет.